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.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38594 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2010-09-09 21:30:36 +00:00
parent bcbde9ce94
commit 0beac2ff04
9 changed files with 370 additions and 162 deletions
+91 -49
View File
@@ -77,6 +77,7 @@ void Controller::Listener::VideoStatsChanged() {}
void Controller::Listener::AudioStatsChanged() {} void Controller::Listener::AudioStatsChanged() {}
void Controller::Listener::PlaybackStateChanged(uint32) {} void Controller::Listener::PlaybackStateChanged(uint32) {}
void Controller::Listener::PositionChanged(float) {} void Controller::Listener::PositionChanged(float) {}
void Controller::Listener::SeekHandled(int64 seekFrame) {}
void Controller::Listener::VolumeChanged(float) {} void Controller::Listener::VolumeChanged(float) {}
void Controller::Listener::MutedChanged(bool) {} void Controller::Listener::MutedChanged(bool) {}
@@ -108,10 +109,12 @@ Controller::Controller()
fAudioTrackList(4), fAudioTrackList(4),
fVideoTrackList(2), fVideoTrackList(2),
fPosition(0), fCurrentFrame(0),
fDuration(0), fDuration(0),
fVideoFrameRate(25.0), fVideoFrameRate(25.0),
fSeekRequested(false),
fPendingSeekRequests(0),
fSeekFrame(-1),
fGlobalSettingsListener(this), fGlobalSettingsListener(this),
@@ -167,12 +170,7 @@ Controller::MessageReceived(BMessage* message)
int64 int64
Controller::Duration() Controller::Duration()
{ {
// This should really be total frames (video frames at that) return _FrameDuration();
// 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);
} }
@@ -258,11 +256,12 @@ Controller::SetTo(const PlaylistItemRef& item)
fVideoTrackSupplier = NULL; fVideoTrackSupplier = NULL;
fAudioTrackSupplier = NULL; fAudioTrackSupplier = NULL;
fCurrentFrame = 0;
fDuration = 0; fDuration = 0;
fVideoFrameRate = 25.0; fVideoFrameRate = 25.0;
fPendingSeekRequests = 0;
fSeekFrame = -1; fSeekFrame = -1;
fSeekRequested = false;
if (fItem.Get() == NULL) if (fItem.Get() == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -641,7 +640,7 @@ Controller::TimePosition()
{ {
BAutolock _(this); BAutolock _(this);
return fPosition; return _TimePosition();
} }
@@ -649,8 +648,7 @@ void
Controller::SetVolume(float value) Controller::SetVolume(float value)
{ {
// printf("Controller::SetVolume %.4f\n", value); // printf("Controller::SetVolume %.4f\n", value);
if (!Lock()) BAutolock _(this);
return;
value = max_c(0.0, min_c(2.0, value)); value = max_c(0.0, min_c(2.0, value));
@@ -663,8 +661,6 @@ Controller::SetVolume(float value)
_NotifyVolumeChanged(fVolume); _NotifyVolumeChanged(fVolume);
} }
Unlock();
} }
void void
@@ -684,8 +680,7 @@ Controller::VolumeDown()
void void
Controller::ToggleMute() Controller::ToggleMute()
{ {
if (!Lock()) BAutolock _(this);
return;
fMuted = !fMuted; fMuted = !fMuted;
@@ -695,8 +690,6 @@ Controller::ToggleMute()
fAudioSupplier->SetVolume(fVolume); fAudioSupplier->SetVolume(fVolume);
_NotifyMutedChanged(fMuted); _NotifyMutedChanged(fMuted);
Unlock();
} }
@@ -709,40 +702,50 @@ Controller::Volume()
} }
void int64
Controller::SetPosition(float value) Controller::SetPosition(float value)
{ {
BAutolock _(this); BAutolock _(this);
SetFramePosition(Duration() * value); return SetFramePosition(_FrameDuration() * value);
} }
void int64
Controller::SetFramePosition(int32 value) Controller::SetFramePosition(int64 value)
{ {
BAutolock _(this); BAutolock _(this);
int64 seekFrame = max_c(0, min_c(Duration(), value)); fPendingSeekRequests++;
int64 currentFrame = CurrentFrame(); fSeekFrame = max_c(0, min_c(_FrameDuration(), value));
// Snap to video keyframe, since that will be the fastest // Snap to video keyframe, since that will be the fastest
// to display and seeking will feel more snappy. // to display and seeking will feel more snappy.
if (Duration() > 240 && fVideoTrackSupplier != NULL) if (Duration() > 240 && fVideoTrackSupplier != NULL)
fVideoTrackSupplier->FindKeyFrameForFrame(&seekFrame); fVideoTrackSupplier->FindKeyFrameForFrame(&fSeekFrame);
if (seekFrame != currentFrame) {
fSeekFrame = seekFrame; int64 currentFrame = CurrentFrame();
fSeekRequested = true; //printf("SetFramePosition(%lld) -> %lld (current: %lld, duration: %lld) "
SetCurrentFrame(seekFrame); //"(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) Controller::SetTimePosition(bigtime_t value)
{ {
BAutolock _(this); BAutolock _(this);
SetPosition((float)value / TimeDuration()); return SetPosition((float)value / TimeDuration());
} }
@@ -924,6 +927,39 @@ Controller::_PlaybackState(int32 playingMode) const
} }
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 // #pragma mark - Notifications
@@ -1023,6 +1059,18 @@ Controller::_NotifyPositionChanged(float position) const
} }
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 void
Controller::_NotifyVolumeChanged(float volume) const Controller::_NotifyVolumeChanged(float volume) const
{ {
@@ -1084,20 +1132,8 @@ Controller::NotifyFPSChanged(float fps) const
void void
Controller::NotifyCurrentFrameChanged(int64 frame) const Controller::NotifyCurrentFrameChanged(int64 frame) const
{ {
// check if we are still waiting to reach the seekframe, fCurrentFrame = frame;
// don't pass the event on to the listeners in that case _NotifyPositionChanged((float)_TimePosition() / fDuration);
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);
} }
@@ -1124,9 +1160,15 @@ Controller::NotifyStopFrameReached() const
void void
Controller::NotifySeekHandled() const Controller::NotifySeekHandled(int64 seekedFrame) const
{ {
fSeekRequested = false; if (fPendingSeekRequests == 0)
fSeekFrame = -1; return;
fPendingSeekRequests--;
if (fPendingSeekRequests == 0)
fSeekFrame = -1;
_NotifySeekHandled(seekedFrame);
} }
+12 -7
View File
@@ -66,6 +66,7 @@ public:
virtual void PlaybackStateChanged(uint32 state); virtual void PlaybackStateChanged(uint32 state);
virtual void PositionChanged(float position); virtual void PositionChanged(float position);
virtual void SeekHandled(int64 seekFrame);
virtual void VolumeChanged(float volume); virtual void VolumeChanged(float volume);
virtual void MutedChanged(bool muted); virtual void MutedChanged(bool muted);
}; };
@@ -117,9 +118,10 @@ public:
void VolumeUp(); void VolumeUp();
void VolumeDown(); void VolumeDown();
void ToggleMute(); void ToggleMute();
void SetPosition(float value);
void SetFramePosition(int32 frame); int64 SetPosition(float value);
void SetTimePosition(bigtime_t position); int64 SetFramePosition(int64 frame);
int64 SetTimePosition(bigtime_t position);
bool HasFile(); bool HasFile();
status_t GetFileFormatInfo( status_t GetFileFormatInfo(
@@ -145,6 +147,8 @@ private:
void _AdoptGlobalSettings(); void _AdoptGlobalSettings();
uint32 _PlaybackState(int32 playingMode) const; uint32 _PlaybackState(int32 playingMode) const;
int64 _FrameDuration() const;
bigtime_t _TimePosition() const;
void _NotifyFileChanged(PlaylistItem* item, void _NotifyFileChanged(PlaylistItem* item,
status_t result) const; status_t result) const;
@@ -157,6 +161,7 @@ private:
void _NotifyPlaybackStateChanged(uint32 state) const; void _NotifyPlaybackStateChanged(uint32 state) const;
void _NotifyPositionChanged(float position) const; void _NotifyPositionChanged(float position) const;
void _NotifySeekHandled(int64 seekFrame) const;
void _NotifyVolumeChanged(float volume) const; void _NotifyVolumeChanged(float volume) const;
void _NotifyMutedChanged(bool muted) const; void _NotifyMutedChanged(bool muted) const;
@@ -172,7 +177,7 @@ private:
virtual void NotifySpeedChanged(float speed) const; virtual void NotifySpeedChanged(float speed) const;
virtual void NotifyFrameDropped() const; virtual void NotifyFrameDropped() const;
virtual void NotifyStopFrameReached() const; virtual void NotifyStopFrameReached() const;
virtual void NotifySeekHandled() const; virtual void NotifySeekHandled(int64 seekedFrame) const;
VideoView* fVideoView; VideoView* fVideoView;
@@ -191,12 +196,12 @@ private:
BList fAudioTrackList; BList fAudioTrackList;
BList fVideoTrackList; BList fVideoTrackList;
mutable bigtime_t fPosition; mutable int64 fCurrentFrame;
bigtime_t fDuration; bigtime_t fDuration;
float fVideoFrameRate; float fVideoFrameRate;
mutable bool fSeekRequested; mutable int32 fPendingSeekRequests;
mutable int32 fSeekFrame; mutable int64 fSeekFrame;
ListenerAdapter fGlobalSettingsListener; ListenerAdapter fGlobalSettingsListener;
@@ -133,6 +133,19 @@ ControllerObserver::PositionChanged(float position)
} }
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 void
ControllerObserver::VolumeChanged(float volume) ControllerObserver::VolumeChanged(float volume)
{ {
@@ -25,6 +25,7 @@ enum {
MSG_CONTROLLER_PLAYBACK_STATE_CHANGED = 'cnps', MSG_CONTROLLER_PLAYBACK_STATE_CHANGED = 'cnps',
MSG_CONTROLLER_POSITION_CHANGED = 'cnpc', MSG_CONTROLLER_POSITION_CHANGED = 'cnpc',
MSG_CONTROLLER_SEEK_HANDLED = 'cnsh',
MSG_CONTROLLER_VOLUME_CHANGED = 'cnvc', MSG_CONTROLLER_VOLUME_CHANGED = 'cnvc',
MSG_CONTROLLER_MUTED_CHANGED = 'cnmc' MSG_CONTROLLER_MUTED_CHANGED = 'cnmc'
}; };
@@ -60,6 +61,7 @@ public:
virtual void PlaybackStateChanged(uint32 state); virtual void PlaybackStateChanged(uint32 state);
virtual void PositionChanged(float position); virtual void PositionChanged(float position);
virtual void SeekHandled(int64 seekFrame);
virtual void VolumeChanged(float volume); virtual void VolumeChanged(float volume);
virtual void MutedChanged(bool muted); virtual void MutedChanged(bool muted);
+69 -21
View File
@@ -81,6 +81,7 @@ enum {
M_VOLUME_DOWN, M_VOLUME_DOWN,
M_SKIP_NEXT, M_SKIP_NEXT,
M_SKIP_PREV, M_SKIP_PREV,
M_WIND,
// The common display aspect ratios // The common display aspect ratios
M_ASPECT_SAME_AS_SOURCE, M_ASPECT_SAME_AS_SOURCE,
@@ -179,7 +180,8 @@ MainWin::MainWin(bool isFirstWindow, BMessage* message)
fMouseMoveDist(0), fMouseMoveDist(0),
fGlobalSettingsListener(this), fGlobalSettingsListener(this),
fInitialSeekPosition(0) fInitialSeekPosition(0),
fAllowWinding(true)
{ {
// Handle window position and size depending on whether this is the // Handle window position and size depending on whether this is the
// first window or not. Use the window size from the window that was // first window or not. Use the window size from the window that was
@@ -675,9 +677,13 @@ MainWin::MessageReceived(BMessage* msg)
if (msg->FindFloat("position", &position) == B_OK) { if (msg->FindFloat("position", &position) == B_OK) {
fControls->SetPosition(position, fController->TimePosition(), fControls->SetPosition(position, fController->TimePosition(),
fController->TimeDuration()); fController->TimeDuration());
fAllowWinding = true;
} }
break; break;
} }
case MSG_CONTROLLER_SEEK_HANDLED:
break;
case MSG_CONTROLLER_VOLUME_CHANGED: case MSG_CONTROLLER_VOLUME_CHANGED:
{ {
float volume; float volume;
@@ -782,6 +788,32 @@ MainWin::MessageReceived(BMessage* msg)
fControls->SkipBackward(); fControls->SkipBackward();
break; 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: case M_VOLUME_UP:
fController->VolumeUp(); fController->VolumeUp();
break; break;
@@ -1248,6 +1280,10 @@ MainWin::_PlaylistItemOpened(const PlaylistItemRef& item, status_t result)
fHasAudio = fController->AudioTrackCount() != 0; fHasAudio = fController->AudioTrackCount() != 0;
SetTitle(item->Name().String()); SetTitle(item->Name().String());
if (fInitialSeekPosition < 0) {
fInitialSeekPosition
= fController->TimeDuration() + fInitialSeekPosition;
}
fController->SetTimePosition(fInitialSeekPosition); fController->SetTimePosition(fInitialSeekPosition);
fInitialSeekPosition = 0; fInitialSeekPosition = 0;
} }
@@ -1401,7 +1437,7 @@ MainWin::_CreateMenu()
new BMessage(M_TOGGLE_NO_INTERFACE), 'B'); new BMessage(M_TOGGLE_NO_INTERFACE), 'B');
fSettingsMenu->AddItem(fNoInterfaceMenuItem); fSettingsMenu->AddItem(fNoInterfaceMenuItem);
fSettingsMenu->AddItem(new BMenuItem("Always on top", 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(); fSettingsMenu->AddSeparatorItem();
item = new BMenuItem("Settings"B_UTF8_ELLIPSIS, item = new BMenuItem("Settings"B_UTF8_ELLIPSIS,
new BMessage(M_SETTINGS), 'S'); new BMessage(M_SETTINGS), 'S');
@@ -1872,8 +1908,8 @@ MainWin::_KeyDown(BMessage* msg)
uint32 rawChar = msg->FindInt32("raw_char"); uint32 rawChar = msg->FindInt32("raw_char");
uint32 modifier = msg->FindInt32("modifiers"); uint32 modifier = msg->FindInt32("modifiers");
printf("key 0x%lx, rawChar 0x%lx, modifiers 0x%lx\n", key, rawChar, // printf("key 0x%lx, rawChar 0x%lx, modifiers 0x%lx\n", key, rawChar,
modifier); // modifier);
// ignore the system modifier namespace // ignore the system modifier namespace
if ((modifier & (B_CONTROL_KEY | B_COMMAND_KEY)) if ((modifier & (B_CONTROL_KEY | B_COMMAND_KEY))
@@ -1923,16 +1959,28 @@ MainWin::_KeyDown(BMessage* msg)
case B_RIGHT_ARROW: case B_RIGHT_ARROW:
if ((modifier & B_COMMAND_KEY) != 0) if ((modifier & B_COMMAND_KEY) != 0)
PostMessage(M_VOLUME_UP);
else
PostMessage(M_SKIP_NEXT); 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; return true;
case B_LEFT_ARROW: case B_LEFT_ARROW:
if ((modifier & B_COMMAND_KEY) != 0) if ((modifier & B_COMMAND_KEY) != 0)
PostMessage(M_VOLUME_DOWN);
else
PostMessage(M_SKIP_PREV); 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; return true;
case B_PAGE_UP: case B_PAGE_UP:
@@ -1942,6 +1990,19 @@ MainWin::_KeyDown(BMessage* msg)
case B_PAGE_DOWN: case B_PAGE_DOWN:
PostMessage(M_SKIP_PREV); PostMessage(M_SKIP_PREV);
return true; 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) { switch (key) {
@@ -1976,19 +2037,6 @@ MainWin::_KeyDown(BMessage* msg)
case 0x48: // numeric keypad left arrow case 0x48: // numeric keypad left arrow
PostMessage(M_SKIP_PREV); PostMessage(M_SKIP_PREV);
return true; 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; return false;
+1
View File
@@ -189,6 +189,7 @@ private:
bool fLoopMovies; bool fLoopMovies;
bool fLoopSounds; bool fLoopSounds;
bigtime_t fInitialSeekPosition; bigtime_t fInitialSeekPosition;
bool fAllowWinding;
static int sNoVideoWidth; static int sNoVideoWidth;
}; };
@@ -83,7 +83,8 @@ NodeManager::Init(BRect videoBounds, float videoFrameRate,
float speed, uint32 enabledNodes, bool useOverlays) float speed, uint32 enabledNodes, bool useOverlays)
{ {
// init base class // init base class
PlaybackManager::Init(videoFrameRate, loopingMode, loopingEnabled, speed); PlaybackManager::Init(videoFrameRate, true, loopingMode, loopingEnabled,
speed);
// get some objects from a derived class // get some objects from a derived class
if (fVideoTarget == NULL) if (fVideoTarget == NULL)
@@ -142,15 +143,18 @@ NodeManager::FormatChanged(BRect videoBounds, float videoFrameRate,
// TODO: if enabledNodes would indicate that audio or video // TODO: if enabledNodes would indicate that audio or video
// is no longer needed, or, worse yet, suddenly needed when // is no longer needed, or, worse yet, suddenly needed when
// it wasn't before, then we should not return here! // 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; return B_OK;
} }
PlaybackManager::Init(videoFrameRate, LoopMode(), IsLoopingEnabled(),
Speed(), MODE_PLAYING_PAUSED_FORWARD, CurrentFrame());
_StopNodes(); _StopNodes();
_TearDownNodes(); _TearDownNodes();
PlaybackManager::Init(videoFrameRate, true, LoopMode(), IsLoopingEnabled(),
Speed(), MODE_PLAYING_PAUSED_FORWARD, CurrentFrame());
SetVideoBounds(videoBounds); SetVideoBounds(videoBounds);
status_t ret = _SetUpNodes(preferredVideoFormat, enabledNodes, status_t ret = _SetUpNodes(preferredVideoFormat, enabledNodes,
@@ -36,6 +36,9 @@ tdebug(const char* str)
} }
#define SUPPORT_SPEED_CHANGES 0
struct PlaybackManager::PlayingState { struct PlaybackManager::PlayingState {
int64 start_frame; int64 start_frame;
int64 end_frame; int64 end_frame;
@@ -75,6 +78,7 @@ struct PlaybackManager::PlayingState {
}; };
#if SUPPORT_SPEED_CHANGES
struct PlaybackManager::SpeedInfo { struct PlaybackManager::SpeedInfo {
int64 activation_frame; // absolute video frame int64 activation_frame; // absolute video frame
bigtime_t activation_time; // performance time bigtime_t activation_time; // performance time
@@ -82,22 +86,25 @@ struct PlaybackManager::SpeedInfo {
// is 1.0 if not playing // is 1.0 if not playing
float set_speed; // speed set by the user float set_speed; // speed set by the user
}; };
#endif
// #pragma mark - PlaybackManager // #pragma mark - PlaybackManager
PlaybackManager::PlaybackManager() PlaybackManager::PlaybackManager()
: BLooper("playback manager"), :
fStates(10), BLooper("playback manager"),
fSpeeds(10), fStates(10),
fCurrentAudioTime(0), fSpeeds(10),
fCurrentVideoTime(0), fCurrentAudioTime(0),
fPerformanceTime(0), fCurrentVideoTime(0),
fFrameRate(1.0), fPerformanceTime(0),
fStopPlayingFrame(-1), fPerformanceTimeEvent(NULL),
fListeners(), fFrameRate(1.0),
fNoAudio(false) fStopPlayingFrame(-1),
fListeners(),
fNoAudio(false)
{ {
Run(); Run();
} }
@@ -110,19 +117,23 @@ PlaybackManager::~PlaybackManager()
void void
PlaybackManager::Init(float frameRate, int32 loopingMode, bool loopingEnabled, PlaybackManager::Init(float frameRate, bool initPerformanceTimes,
float playbackSpeed, int32 playMode, int32 currentFrame) int32 loopingMode, bool loopingEnabled, float playbackSpeed,
int32 playMode, int32 currentFrame)
{ {
// cleanup first // cleanup first
Cleanup(); Cleanup();
// set the new frame rate // set the new frame rate
fFrameRate = frameRate; fFrameRate = frameRate;
fCurrentAudioTime = 0; if (initPerformanceTimes) {
fCurrentVideoTime = 0; fCurrentAudioTime = 0;
fPerformanceTime = 0; fCurrentVideoTime = 0;
fPerformanceTime = 0;
}
fStopPlayingFrame = -1; fStopPlayingFrame = -1;
#if SUPPORT_SPEED_CHANGES
// set up the initial speed // set up the initial speed
SpeedInfo* speed = new SpeedInfo; SpeedInfo* speed = new SpeedInfo;
speed->activation_frame = 0; speed->activation_frame = 0;
@@ -130,6 +141,7 @@ PlaybackManager::Init(float frameRate, int32 loopingMode, bool loopingEnabled,
speed->speed = playbackSpeed; speed->speed = playbackSpeed;
speed->set_speed = playbackSpeed; speed->set_speed = playbackSpeed;
_PushSpeedInfo(speed); _PushSpeedInfo(speed);
#endif
// set up the initial state // set up the initial state
PlayingState* state = new PlayingState; PlayingState* state = new PlayingState;
@@ -165,15 +177,20 @@ PlaybackManager::Init(float frameRate, int32 loopingMode, bool loopingEnabled,
void void
PlaybackManager::Cleanup() PlaybackManager::Cleanup()
{ {
if (EventQueue::Default().RemoveEvent(fPerformanceTimeEvent))
delete fPerformanceTimeEvent;
fPerformanceTimeEvent = NULL;
// delete states // delete states
for (int32 i = 0; PlayingState* state = _StateAt(i); i++) for (int32 i = 0; PlayingState* state = _StateAt(i); i++)
delete state; delete state;
fStates.MakeEmpty(); fStates.MakeEmpty();
#if SUPPORT_SPEED_CHANGES
// delete speed infos // delete speed infos
for (int32 i = 0; SpeedInfo* speed = _SpeedInfoAt(i); i++) for (int32 i = 0; SpeedInfo* speed = _SpeedInfoAt(i); i++)
delete speed; delete speed;
fSpeeds.MakeEmpty(); fSpeeds.MakeEmpty();
#endif
} }
@@ -182,9 +199,25 @@ PlaybackManager::MessageReceived(BMessage* message)
{ {
switch (message->what) { switch (message->what) {
case MSG_EVENT: 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; break;
}
case MSG_PLAYBACK_FORCE_UPDATE: case MSG_PLAYBACK_FORCE_UPDATE:
{ {
@@ -333,9 +366,13 @@ PlaybackManager::CurrentFrame() const
float float
PlaybackManager::Speed() const PlaybackManager::Speed() const
{ {
#if SUPPORT_SPEED_CHANGES
if (!_LastState()) if (!_LastState())
return 1.0; return 1.0;
return _LastSpeedInfo()->set_speed; return _LastSpeedInfo()->set_speed;
#else
return 1.0;
#endif
} }
@@ -384,8 +421,8 @@ PlaybackManager::DurationChanged()
void void
PlaybackManager::SetCurrentFrame(int64 frame) PlaybackManager::SetCurrentFrame(int64 frame)
{ {
if (_LastState()->current_frame == frame) { if (CurrentFrame() == frame) {
NotifySeekHandled(); NotifySeekHandled(frame);
return; return;
} }
PlayingState* newState = new PlayingState(*_LastState()); PlayingState* newState = new PlayingState(*_LastState());
@@ -465,6 +502,7 @@ PlaybackManager::SetLoopingEnabled(bool enabled, bool continuePlaying)
void void
PlaybackManager::SetSpeed(float speed) PlaybackManager::SetSpeed(float speed)
{ {
#if SUPPORT_SPEED_CHANGES
SpeedInfo* lastSpeed = _LastSpeedInfo(); SpeedInfo* lastSpeed = _LastSpeedInfo();
if (speed != lastSpeed->set_speed) { if (speed != lastSpeed->set_speed) {
SpeedInfo* info = new SpeedInfo(*lastSpeed); SpeedInfo* info = new SpeedInfo(*lastSpeed);
@@ -476,6 +514,7 @@ PlaybackManager::SetSpeed(float speed)
info->speed = 1.0; info->speed = 1.0;
_PushSpeedInfo(info); _PushSpeedInfo(info);
} }
#endif
} }
@@ -676,10 +715,12 @@ PlaybackManager::NextChangeFrame(int64 startFrame, int64 endFrame) const
int32 endIndex = _IndexForFrame(endFrame); int32 endIndex = _IndexForFrame(endFrame);
if (startIndex < endIndex) if (startIndex < endIndex)
endFrame = _StateAt(startIndex + 1)->activation_frame; endFrame = _StateAt(startIndex + 1)->activation_frame;
#if SUPPORT_SPEED_CHANGES
startIndex = _SpeedInfoIndexForFrame(startFrame); startIndex = _SpeedInfoIndexForFrame(startFrame);
endIndex = _SpeedInfoIndexForFrame(endFrame); endIndex = _SpeedInfoIndexForFrame(endFrame);
if (startIndex < endIndex) if (startIndex < endIndex)
endFrame = _SpeedInfoAt(startIndex + 1)->activation_frame; endFrame = _SpeedInfoAt(startIndex + 1)->activation_frame;
#endif
return endFrame; return endFrame;
} }
@@ -693,10 +734,12 @@ PlaybackManager::NextChangeTime(bigtime_t startTime, bigtime_t endTime) const
int32 endIndex = _IndexForTime(endTime); int32 endIndex = _IndexForTime(endTime);
if (startIndex < endIndex) if (startIndex < endIndex)
endTime = TimeForFrame(_StateAt(startIndex + 1)->activation_frame); endTime = TimeForFrame(_StateAt(startIndex + 1)->activation_frame);
#if SUPPORT_SPEED_CHANGES
startIndex = _SpeedInfoIndexForTime(startTime); startIndex = _SpeedInfoIndexForTime(startTime);
endIndex = _SpeedInfoIndexForTime(endTime); endIndex = _SpeedInfoIndexForTime(endTime);
if (startIndex < endIndex) if (startIndex < endIndex)
endTime = TimeForFrame(_SpeedInfoAt(startIndex + 1)->activation_frame); endTime = TimeForFrame(_SpeedInfoAt(startIndex + 1)->activation_frame);
#endif
return endTime; return endTime;
} }
@@ -751,7 +794,9 @@ PlaybackManager::GetPlaylistTimeInterval(bigtime_t startTime,
// be greater than necessary, but that doesn't harm. // be greater than necessary, but that doesn't harm.
int64 startFrame = FrameForTime(startTime); int64 startFrame = FrameForTime(startTime);
int64 endFrame = FrameForTime(endTime) + 1; 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. // Get the Playlist frame interval that belongs to the frame interval.
int64 xStartFrame; int64 xStartFrame;
int64 xEndFrame; int64 xEndFrame;
@@ -769,33 +814,37 @@ PlaybackManager::GetPlaylistTimeInterval(bigtime_t startTime,
// forward // forward
case 1: case 1:
{ {
// xStartTime = PlaylistTimeForFrame(xStartFrame) #if SUPPORT_SPEED_CHANGES
// + startTime - TimeForFrame(startFrame);
// xEndTime = xStartTime + intervalLength;
// TODO: The current method does not handle the times the same way. // TODO: The current method does not handle the times the same way.
// It may happen, that for the same performance time different // It may happen, that for the same performance time different
// Playlist times (within a frame) are returned when passing it // Playlist times (within a frame) are returned when passing it
// one time as a start time and another time as an end time. // one time as a start time and another time as an end time.
xStartTime = PlaylistTimeForFrame(xStartFrame) xStartTime = PlaylistTimeForFrame(xStartFrame)
+ bigtime_t(double(startTime - TimeForFrame(startFrame)) + bigtime_t(double(startTime - TimeForFrame(startFrame))
* info->speed); * info->speed);
xEndTime = xStartTime 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; break;
} }
// backward // backward
case -1: case -1:
{ {
// xEndTime = PlaylistTimeForFrame(xEndFrame) #if SUPPORT_SPEED_CHANGES
// - startTime + TimeForFrame(startFrame);
// xStartTime = xEndTime - intervalLength;
xEndTime = PlaylistTimeForFrame(xEndFrame) xEndTime = PlaylistTimeForFrame(xEndFrame)
- bigtime_t(double(startTime - TimeForFrame(startFrame)) - bigtime_t(double(startTime - TimeForFrame(startFrame))
* info->speed); * info->speed);
xStartTime = xEndTime 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; break;
} }
// not playing // not playing
@@ -805,7 +854,11 @@ PlaybackManager::GetPlaylistTimeInterval(bigtime_t startTime,
xEndTime = xStartTime; xEndTime = xStartTime;
break; break;
} }
#if SUPPORT_SPEED_CHANGES
playingSpeed = (float)playingDirection * info->speed; playingSpeed = (float)playingDirection * info->speed;
#else
playingSpeed = (float)playingDirection;
#endif
} }
@@ -815,11 +868,10 @@ int64
PlaybackManager::FrameForTime(bigtime_t time) const PlaybackManager::FrameForTime(bigtime_t time) const
{ {
//TRACE("PlaybackManager::FrameForTime(%lld)\n", time); //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 // In order to avoid problems caused by rounding errors, we check
// if for the resulting frame holds // if for the resulting frame holds
// TimeForFrame(frame) <= time < TimeForFrame(frame + 1). // TimeForFrame(frame) <= time < TimeForFrame(frame + 1).
// int64 frame = (int64)((double)time * (double)fFrameRate / 1000000.0); #if SUPPORT_SPEED_CHANGES
SpeedInfo* info = _SpeedInfoForTime(time); SpeedInfo* info = _SpeedInfoForTime(time);
if (!info) { if (!info) {
fprintf(stderr, "PlaybackManager::FrameForTime() - no SpeedInfo!\n"); fprintf(stderr, "PlaybackManager::FrameForTime() - no SpeedInfo!\n");
@@ -828,6 +880,10 @@ if (!info) {
int64 frame = (int64)(((double)time - info->activation_time) int64 frame = (int64)(((double)time - info->activation_time)
* (double)fFrameRate * info->speed / 1000000.0) * (double)fFrameRate * info->speed / 1000000.0)
+ info->activation_frame; + info->activation_frame;
#else
int64 frame = (int64)((double)time * (double)fFrameRate / 1000000.0);
#endif
if (TimeForFrame(frame) > time) if (TimeForFrame(frame) > time)
frame--; frame--;
else if (TimeForFrame(frame + 1) <= time) else if (TimeForFrame(frame + 1) <= time)
@@ -843,19 +899,18 @@ if (!info) {
bigtime_t bigtime_t
PlaybackManager::TimeForFrame(int64 frame) const PlaybackManager::TimeForFrame(int64 frame) const
{ {
// return (bigtime_t)((double)frame * 1000000.0 / (double)fFrameRate); #if SUPPORT_SPEED_CHANGES
SpeedInfo* info = _SpeedInfoForFrame(frame); SpeedInfo* info = _SpeedInfoForFrame(frame);
if (!info) { if (!info) {
fprintf(stderr, "PlaybackManager::TimeForFrame() - no SpeedInfo!\n"); fprintf(stderr, "PlaybackManager::TimeForFrame() - no SpeedInfo!\n");
return 0; return 0;
} }
// return (bigtime_t)((double)(frame - info->activation_frame) * 1000000.0 return (bigtime_t)((double)(frame - info->activation_frame) * 1000000.0
// / ((double)fFrameRate * info->speed)) / ((double)fFrameRate * info->speed))
// + info->activation_time; + info->activation_time;
bigtime_t result = (bigtime_t)((double)(frame - info->activation_frame) * 1000000.0 #else
/ ((double)fFrameRate * info->speed)) + info->activation_time; return (bigtime_t)((double)frame * 1000000.0 / (double)fFrameRate);
//fprintf(stderr, "PlaybackManager::TimeForFrame(%lld): %lld\n", frame, result); #endif
return result;
} }
@@ -892,11 +947,13 @@ PlaybackManager::SetCurrentAudioTime(bigtime_t time)
TRACE("PlaybackManager::SetCurrentAudioTime(%lld)\n", time); TRACE("PlaybackManager::SetCurrentAudioTime(%lld)\n", time);
bigtime_t lastFrameTime = _TimeForLastFrame(); bigtime_t lastFrameTime = _TimeForLastFrame();
fCurrentAudioTime = time; fCurrentAudioTime = time;
// _UpdateStates();
bigtime_t newLastFrameTime = _TimeForLastFrame(); bigtime_t newLastFrameTime = _TimeForLastFrame();
if (lastFrameTime != newLastFrameTime) { if (lastFrameTime != newLastFrameTime) {
bigtime_t eventTime = RealTimeForTime(newLastFrameTime); if (fPerformanceTimeEvent == NULL) {
EventQueue::Default().AddEvent(new MessageEvent(eventTime, this)); bigtime_t eventTime = RealTimeForTime(newLastFrameTime);
fPerformanceTimeEvent = new MessageEvent(eventTime, this);
EventQueue::Default().AddEvent(fPerformanceTimeEvent);
}
_CheckStopPlaying(); _CheckStopPlaying();
} }
} }
@@ -917,11 +974,13 @@ PlaybackManager::SetCurrentVideoTime(bigtime_t time)
TRACE("PlaybackManager::SetCurrentVideoTime(%lld)\n", time); TRACE("PlaybackManager::SetCurrentVideoTime(%lld)\n", time);
bigtime_t lastFrameTime = _TimeForLastFrame(); bigtime_t lastFrameTime = _TimeForLastFrame();
fCurrentVideoTime = time; fCurrentVideoTime = time;
// _UpdateStates();
bigtime_t newLastFrameTime = _TimeForLastFrame(); bigtime_t newLastFrameTime = _TimeForLastFrame();
if (lastFrameTime != newLastFrameTime) { if (lastFrameTime != newLastFrameTime) {
bigtime_t eventTime = RealTimeForTime(newLastFrameTime); if (fPerformanceTimeEvent == NULL) {
EventQueue::Default().AddEvent(new MessageEvent(eventTime, this)); bigtime_t eventTime = RealTimeForTime(newLastFrameTime);
fPerformanceTimeEvent = new MessageEvent(eventTime, this);
EventQueue::Default().AddEvent(fPerformanceTimeEvent);
}
_CheckStopPlaying(); _CheckStopPlaying();
} }
} }
@@ -931,11 +990,11 @@ TRACE("PlaybackManager::SetCurrentVideoTime(%lld)\n", time);
void void
PlaybackManager::SetPerformanceFrame(int64 frame) 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. */ argument. */
void void
PlaybackManager::SetPerformanceTime(bigtime_t time) PlaybackManager::SetPerformanceTime(bigtime_t time)
@@ -1089,7 +1148,7 @@ PlaybackManager::NotifyStopFrameReached() const
void void
PlaybackManager::NotifySeekHandled() const PlaybackManager::NotifySeekHandled(int64 frame) const
{ {
// not currently implemented in PlaybackListener interface // not currently implemented in PlaybackListener interface
} }
@@ -1175,6 +1234,7 @@ CurrentFrame(), currentFrame);
fStates.RemoveItem(fStates.CountItems() - 1); fStates.RemoveItem(fStates.CountItems() - 1);
TRACE("deleting last \n"); TRACE("deleting last \n");
PrintState(lastState); PrintState(lastState);
_NotifySeekHandledIfNecessary(lastState);
delete lastState; delete lastState;
} else { } else {
// it is -- keep it // it is -- keep it
@@ -1199,6 +1259,7 @@ PrintState(lastState);
fStates.AddItem(state); fStates.AddItem(state);
PrintState(state); PrintState(state);
TRACE("_PushState: state count: %ld\n", fStates.CountItems()); TRACE("_PushState: state count: %ld\n", fStates.CountItems());
#if SUPPORT_SPEED_CHANGES
// push a new speed info // push a new speed info
SpeedInfo* speedInfo = new SpeedInfo(*_LastSpeedInfo()); SpeedInfo* speedInfo = new SpeedInfo(*_LastSpeedInfo());
if (playingDirection == 0) if (playingDirection == 0)
@@ -1207,6 +1268,7 @@ TRACE("_PushState: state count: %ld\n", fStates.CountItems());
speedInfo->speed = speedInfo->set_speed; speedInfo->speed = speedInfo->set_speed;
speedInfo->activation_frame = state->activation_frame; speedInfo->activation_frame = state->activation_frame;
_PushSpeedInfo(speedInfo); _PushSpeedInfo(speedInfo);
#endif
// If the new state is a playing state and looping is turned off, // If the new state is a playing state and looping is turned off,
// determine when playing shall stop. // determine when playing shall stop.
if (playingDirection != 0 && !state->looping_enabled) { if (playingDirection != 0 && !state->looping_enabled) {
@@ -1252,19 +1314,18 @@ PlaybackManager::_UpdateStates()
// Performance time should always be the least one. // Performance time should always be the least one.
int32 firstActive = _IndexForTime(fPerformanceTime); int32 firstActive = _IndexForTime(fPerformanceTime);
//TRACE("firstActive: %ld, numStates: %ld\n", firstActive, fStates.CountItems()); //TRACE("firstActive: %ld, numStates: %ld\n", firstActive, fStates.CountItems());
for (int32 i = 0; i < firstActive; i++) for (int32 i = 0; i < firstActive; i++) {
delete _StateAt(i); PlayingState* state = _StateAt(i);
_NotifySeekHandledIfNecessary(state);
delete state;
}
if (firstActive > 0) if (firstActive > 0)
{ {
fStates.RemoveItems(0, firstActive); fStates.RemoveItems(0, firstActive);
TRACE("_UpdateStates: states removed: %ld, state count: %ld\n", TRACE("_UpdateStates: states removed: %ld, state count: %ld\n",
firstActive, fStates.CountItems()); firstActive, fStates.CountItems());
} }
PlayingState* currentState = _StateAt(firstActive); _NotifySeekHandledIfNecessary(_StateAt(0));
if (currentState != NULL && currentState->is_seek_request) {
currentState->is_seek_request = false;
NotifySeekHandled();
}
} }
@@ -1476,7 +1537,7 @@ frameCount);
index = (index % frameCount + frameCount) % frameCount; index = (index % frameCount + frameCount) % frameCount;
// get the frame for the index // get the frame for the index
int32 frame = startFrame; int64 frame = startFrame;
switch (state->loop_mode) { switch (state->loop_mode) {
case LOOPING_ALL: case LOOPING_ALL:
case LOOPING_RANGE: case LOOPING_RANGE:
@@ -1512,38 +1573,48 @@ PlaybackManager::_NextFrameInRange(PlayingState* state, int64 frame)
void void
PlaybackManager::_PushSpeedInfo(SpeedInfo* info) PlaybackManager::_PushSpeedInfo(SpeedInfo* info)
{ {
if (info) { #if SUPPORT_SPEED_CHANGES
// check the last state if (info == NULL)
if (SpeedInfo* lastSpeed = _LastSpeedInfo()) { return;
// set the activation time // check the last state
info->activation_time = TimeForFrame(info->activation_frame); if (SpeedInfo* lastSpeed = _LastSpeedInfo()) {
// Remove the last state, if it won't be activated. // set the activation time
if (lastSpeed->activation_frame == info->activation_frame) { info->activation_time = TimeForFrame(info->activation_frame);
// Remove the last state, if it won't be activated.
if (lastSpeed->activation_frame == info->activation_frame) {
//fprintf(stderr, " replacing last speed info\n"); //fprintf(stderr, " replacing last speed info\n");
fSpeeds.RemoveItem(lastSpeed); fSpeeds.RemoveItem(lastSpeed);
delete lastSpeed; delete lastSpeed;
}
} }
fSpeeds.AddItem(info); }
fSpeeds.AddItem(info);
//fprintf(stderr, " speed info pushed: activation frame: %lld, " //fprintf(stderr, " speed info pushed: activation frame: %lld, "
//"activation time: %lld, speed: %f\n", info->activation_frame, //"activation time: %lld, speed: %f\n", info->activation_frame,
//info->activation_time, info->speed); //info->activation_time, info->speed);
// ... // ...
} #endif
} }
PlaybackManager::SpeedInfo* PlaybackManager::SpeedInfo*
PlaybackManager::_LastSpeedInfo() const PlaybackManager::_LastSpeedInfo() const
{ {
#if SUPPORT_SPEED_CHANGES
return (SpeedInfo*)fSpeeds.ItemAt(fSpeeds.CountItems() - 1); return (SpeedInfo*)fSpeeds.ItemAt(fSpeeds.CountItems() - 1);
#else
return NULL;
#endif
} }
PlaybackManager::SpeedInfo* PlaybackManager::SpeedInfo*
PlaybackManager::_SpeedInfoAt(int32 index) const PlaybackManager::_SpeedInfoAt(int32 index) const
{ {
#if SUPPORT_SPEED_CHANGES
return (SpeedInfo*)fSpeeds.ItemAt(index); return (SpeedInfo*)fSpeeds.ItemAt(index);
#else
return NULL;
#endif
} }
@@ -1551,6 +1622,7 @@ int32
PlaybackManager::_SpeedInfoIndexForFrame(int64 frame) const PlaybackManager::_SpeedInfoIndexForFrame(int64 frame) const
{ {
int32 index = 0; int32 index = 0;
#if SUPPORT_SPEED_CHANGES
SpeedInfo* info; SpeedInfo* info;
while (((info = _SpeedInfoAt(index + 1))) while (((info = _SpeedInfoAt(index + 1)))
&& info->activation_frame <= frame) { && info->activation_frame <= frame) {
@@ -1558,6 +1630,7 @@ PlaybackManager::_SpeedInfoIndexForFrame(int64 frame) const
} }
//fprintf(stderr, "PlaybackManager::_SpeedInfoIndexForFrame(%lld): %ld\n", //fprintf(stderr, "PlaybackManager::_SpeedInfoIndexForFrame(%lld): %ld\n",
//frame, index); //frame, index);
#endif
return index; return index;
} }
@@ -1566,6 +1639,7 @@ int32
PlaybackManager::_SpeedInfoIndexForTime(bigtime_t time) const PlaybackManager::_SpeedInfoIndexForTime(bigtime_t time) const
{ {
int32 index = 0; int32 index = 0;
#if SUPPORT_SPEED_CHANGES
SpeedInfo* info; SpeedInfo* info;
while (((info = _SpeedInfoAt(index + 1))) while (((info = _SpeedInfoAt(index + 1)))
&& info->activation_time <= time) { && info->activation_time <= time) {
@@ -1573,6 +1647,7 @@ PlaybackManager::_SpeedInfoIndexForTime(bigtime_t time) const
} }
//fprintf(stderr, "PlaybackManager::_SpeedInfoIndexForTime(%lld): %ld\n", //fprintf(stderr, "PlaybackManager::_SpeedInfoIndexForTime(%lld): %ld\n",
//time, index); //time, index);
#endif
return index; return index;
} }
@@ -1594,12 +1669,14 @@ PlaybackManager::_SpeedInfoForTime(bigtime_t time) const
void void
PlaybackManager::_UpdateSpeedInfos() PlaybackManager::_UpdateSpeedInfos()
{ {
#if SUPPORT_SPEED_CHANGES
int32 firstActive = _SpeedInfoIndexForTime(fPerformanceTime); int32 firstActive = _SpeedInfoIndexForTime(fPerformanceTime);
for (int32 i = 0; i < firstActive; i++) for (int32 i = 0; i < firstActive; i++)
delete _SpeedInfoAt(i); delete _SpeedInfoAt(i);
if (firstActive > 0) if (firstActive > 0)
fSpeeds.RemoveItems(0, firstActive); fSpeeds.RemoveItems(0, firstActive);
//fprintf(stderr, " speed infos 0 - %ld removed\n", firstActive); //fprintf(stderr, " speed infos 0 - %ld removed\n", firstActive);
#endif
} }
@@ -1635,3 +1712,12 @@ PlaybackManager::_CheckStopPlaying()
} }
} }
void
PlaybackManager::_NotifySeekHandledIfNecessary(PlayingState* state)
{
if (state->is_seek_request) {
state->is_seek_request = false;
NotifySeekHandled(state->current_frame);
}
}
@@ -17,6 +17,7 @@
#include <Rect.h> #include <Rect.h>
class MessageEvent;
class PlaybackListener; class PlaybackListener;
@@ -52,11 +53,13 @@ public:
virtual ~PlaybackManager(); virtual ~PlaybackManager();
void Init(float frameRate, void Init(float frameRate,
int32 loopingMode = LOOPING_ALL, bool initPerformanceTimes,
bool loopingEnabled = true, int32 loopingMode = LOOPING_ALL,
float speed = 1.0, bool loopingEnabled = true,
int32 playMode = MODE_PLAYING_PAUSED_FORWARD, float speed = 1.0,
int32 currentFrame = 0); int32 playMode
= MODE_PLAYING_PAUSED_FORWARD,
int32 currentFrame = 0);
void Cleanup(); void Cleanup();
// BHandler interface // BHandler interface
@@ -132,7 +135,6 @@ public:
int64& xStartFrame, int64& xEndFrame, int64& xStartFrame, int64& xEndFrame,
int32& playingDirection) const; int32& playingDirection) const;
// PlaybackManagerInterface
virtual void GetPlaylistTimeInterval( virtual void GetPlaylistTimeInterval(
bigtime_t startTime, bigtime_t& endTime, bigtime_t startTime, bigtime_t& endTime,
bigtime_t& xStartTime, bigtime_t& xEndTime, bigtime_t& xStartTime, bigtime_t& xEndTime,
@@ -169,7 +171,7 @@ public:
virtual void NotifySpeedChanged(float speed) const; virtual void NotifySpeedChanged(float speed) const;
virtual void NotifyFrameDropped() const; virtual void NotifyFrameDropped() const;
virtual void NotifyStopFrameReached() const; virtual void NotifyStopFrameReached() const;
virtual void NotifySeekHandled() const; virtual void NotifySeekHandled(int64 seekedFrame) const;
// debugging // debugging
void PrintState(PlayingState* state); void PrintState(PlayingState* state);
@@ -215,21 +217,26 @@ public:
bigtime_t _TimeForLastFrame() const; bigtime_t _TimeForLastFrame() const;
bigtime_t _TimeForNextFrame() const; bigtime_t _TimeForNextFrame() const;
void _NotifySeekHandledIfNecessary(
PlayingState* state);
void _CheckStopPlaying(); void _CheckStopPlaying();
private: private:
BList fStates; BList fStates;
BList fSpeeds; BList fSpeeds;
volatile bigtime_t fCurrentAudioTime; volatile bigtime_t fCurrentAudioTime;
volatile bigtime_t fCurrentVideoTime; volatile bigtime_t fCurrentVideoTime;
volatile bigtime_t fPerformanceTime; volatile bigtime_t fPerformanceTime;
MessageEvent* fPerformanceTimeEvent;
volatile float fFrameRate; // video frame rate volatile float fFrameRate; // video frame rate
volatile bigtime_t fStopPlayingFrame; // frame at which playing volatile bigtime_t fStopPlayingFrame; // frame at which playing
// shall be stopped, // shall be stopped,
// disabled: -1 // disabled: -1
BList fListeners; BList fListeners;
protected: protected:
bool fNoAudio; bool fNoAudio;
}; };