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