#include <algorithm>
#include <stdio.h>
#include <Message.h>
#include <OS.h>
#include <Window.h>
#include "EventQueue.h"
#include "MessageEvent.h"
#include "PlaybackListener.h"
#include "PlaybackManager.h"
using namespace std;
#ifdef TRACE_NODE_MANAGER
# define TRACE(x...) printf(x)
# define ERROR(x...) fprintf(stderr, x)
#else
# define TRACE(x...)
# define ERROR(x...) fprintf(stderr, x)
#endif
void
tdebug(const char* str)
{
TRACE("[%lx, %lld] ", find_thread(NULL), system_time());
TRACE(str);
}
#define SUPPORT_SPEED_CHANGES 0
struct PlaybackManager::PlayingState {
int64 start_frame;
int64 end_frame;
int64 frame_count;
int64 first_visible_frame;
int64 last_visible_frame;
int64 max_frame_count;
int32 play_mode;
int32 loop_mode;
bool looping_enabled;
bool is_seek_request;
int64 current_frame;
int64 range_index;
int64 activation_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)
{
}
};
#if SUPPORT_SPEED_CHANGES
struct PlaybackManager::SpeedInfo {
int64 activation_frame;
bigtime_t activation_time;
float speed;
float set_speed;
};
#endif
PlaybackManager::PlaybackManager()
:
BLooper("playback manager"),
fStates(10),
fSpeeds(10),
fCurrentAudioTime(0),
fCurrentVideoTime(0),
fPerformanceTime(0),
fPerformanceTimeEvent(NULL),
fFrameRate(1.0),
fStopPlayingFrame(-1),
fListeners(),
fNoAudio(false)
{
Run();
}
PlaybackManager::~PlaybackManager()
{
Cleanup();
}
void
PlaybackManager::Init(float frameRate, bool initPerformanceTimes,
int32 loopingMode, bool loopingEnabled, float playbackSpeed,
int32 playMode, int32 currentFrame)
{
Cleanup();
fFrameRate = frameRate;
if (initPerformanceTimes) {
fCurrentAudioTime = 0;
fCurrentVideoTime = 0;
fPerformanceTime = 0;
}
fStopPlayingFrame = -1;
#if SUPPORT_SPEED_CHANGES
SpeedInfo* speed = new SpeedInfo;
speed->activation_frame = 0;
speed->activation_time = 0;
speed->speed = playbackSpeed;
speed->set_speed = playbackSpeed;
_PushSpeedInfo(speed);
#endif
PlayingState* state = new PlayingState;
state->frame_count = Duration();
state->start_frame = 0;
state->end_frame = 0;
state->first_visible_frame = 0;
state->last_visible_frame = 0;
state->max_frame_count = state->frame_count;
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);
TRACE("initial state pushed: state count: %ld\n", fStates.CountItems());
NotifyPlayModeChanged(PlayMode());
NotifyLoopModeChanged(LoopMode());
NotifyLoopingEnabledChanged(IsLoopingEnabled());
NotifyVideoBoundsChanged(VideoBounds());
NotifyFPSChanged(FramesPerSecond());
NotifySpeedChanged(Speed());
NotifyCurrentFrameChanged(CurrentFrame());
SetPlayMode(playMode);
}
void
PlaybackManager::Cleanup()
{
if (EventQueue::Default().RemoveEvent(fPerformanceTimeEvent))
delete fPerformanceTimeEvent;
fPerformanceTimeEvent = NULL;
for (int32 i = 0; PlayingState* state = _StateAt(i); i++)
delete state;
fStates.MakeEmpty();
#if SUPPORT_SPEED_CHANGES
for (int32 i = 0; SpeedInfo* speed = _SpeedInfoAt(i); i++)
delete speed;
fSpeeds.MakeEmpty();
#endif
}
void
PlaybackManager::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_EVENT:
{
if (fPerformanceTimeEvent == NULL) {
break;
}
bigtime_t eventTime;
message->FindInt64("time", &eventTime);
fPerformanceTimeEvent = NULL;
SetPerformanceTime(TimeForRealTime(eventTime));
break;
}
case MSG_PLAYBACK_FORCE_UPDATE:
{
int64 frame;
if (message->FindInt64("frame", &frame) < B_OK)
frame = CurrentFrame();
SetCurrentFrame(frame);
break;
}
case MSG_PLAYBACK_SET_RANGE:
{
int64 startFrame = _LastState()->start_frame;
int64 endFrame = _LastState()->end_frame;
message->FindInt64("start frame", &startFrame);
message->FindInt64("end frame", &endFrame);
if (startFrame != _LastState()->start_frame
|| endFrame != _LastState()->end_frame) {
PlayingState* state = new PlayingState(*_LastState());
state->start_frame = startFrame;
state->end_frame = endFrame;
_PushState(state, true);
}
break;
}
case MSG_PLAYBACK_SET_VISIBLE:
{
int64 startFrame = _LastState()->first_visible_frame;
int64 endFrame = _LastState()->last_visible_frame;
message->FindInt64("start frame", &startFrame);
message->FindInt64("end frame", &endFrame);
if (startFrame != _LastState()->first_visible_frame
|| endFrame != _LastState()->last_visible_frame) {
PlayingState* state = new PlayingState(*_LastState());
state->first_visible_frame = startFrame;
state->last_visible_frame = endFrame;
_PushState(state, true);
}
break;
}
case MSG_PLAYBACK_SET_LOOP_MODE:
{
int32 loopMode = _LastState()->loop_mode;
message->FindInt32("mode", &loopMode);
if (loopMode != _LastState()->loop_mode) {
PlayingState* state = new PlayingState(*_LastState());
state->loop_mode = loopMode;
_PushState(state, true);
}
break;
}
default:
BLooper::MessageReceived(message);
break;
}
}
void
PlaybackManager::StartPlaying(bool atBeginning)
{
TRACE("PlaybackManager::StartPlaying()\n");
int32 playMode = PlayMode();
if (playMode == MODE_PLAYING_PAUSED_FORWARD)
SetPlayMode(MODE_PLAYING_FORWARD, !atBeginning);
if (playMode == MODE_PLAYING_PAUSED_BACKWARD)
SetPlayMode(MODE_PLAYING_BACKWARD, !atBeginning);
}
void
PlaybackManager::StopPlaying()
{
TRACE("PlaybackManager::StopPlaying()\n");
int32 playMode = PlayMode();
if (playMode == MODE_PLAYING_FORWARD)
SetPlayMode(MODE_PLAYING_PAUSED_FORWARD, true);
if (playMode == MODE_PLAYING_BACKWARD)
SetPlayMode(MODE_PLAYING_PAUSED_BACKWARD, true);
}
void
PlaybackManager::TogglePlaying(bool atBeginning)
{
SetPlayMode(-PlayMode(), !atBeginning);
}
void
PlaybackManager::PausePlaying()
{
if (PlayMode() > 0)
TogglePlaying();
}
bool
PlaybackManager::IsPlaying() const
{
return (PlayMode() > 0);
}
int32
PlaybackManager::PlayMode() const
{
if (!_LastState())
return MODE_PLAYING_PAUSED_FORWARD;
return _LastState()->play_mode;
}
int32
PlaybackManager::LoopMode() const
{
if (!_LastState())
return LOOPING_ALL;
return _LastState()->loop_mode;
}
bool
PlaybackManager::IsLoopingEnabled() const
{
if (!_LastState())
return true;
return _LastState()->looping_enabled;
}
int64
PlaybackManager::CurrentFrame() const
{
return PlaylistFrameAtFrame(FrameForTime(fPerformanceTime));
}
float
PlaybackManager::Speed() const
{
#if SUPPORT_SPEED_CHANGES
if (!_LastState())
return 1.0;
return _LastSpeedInfo()->set_speed;
#else
return 1.0;
#endif
}
void
PlaybackManager::SetFramesPerSecond(float framesPerSecond)
{
if (framesPerSecond != fFrameRate) {
fFrameRate = framesPerSecond;
NotifyFPSChanged(fFrameRate);
}
}
float
PlaybackManager::FramesPerSecond() const
{
return fFrameRate;
}
void
PlaybackManager::FrameDropped() const
{
NotifyFrameDropped();
}
void
PlaybackManager::DurationChanged()
{
if (!_LastState())
return;
int32 frameCount = Duration();
if (frameCount != _LastState()->frame_count) {
PlayingState* state = new PlayingState(*_LastState());
state->frame_count = frameCount;
state->max_frame_count = frameCount;
_PushState(state, true);
}
}
void
PlaybackManager::SetCurrentFrame(int64 frame)
{
if (CurrentFrame() == frame) {
NotifySeekHandled(frame);
return;
}
PlayingState* newState = new PlayingState(*_LastState());
newState->current_frame = frame;
newState->is_seek_request = true;
_PushState(newState, false);
}
void
PlaybackManager::SetPlayMode(int32 mode, bool continuePlaying)
{
PlayingState* newState = new PlayingState(*_LastState());
newState->play_mode = mode;
if (!continuePlaying && !(_PlayingDirectionFor(newState) == 0))
newState->current_frame = _PlayingStartFrameFor(newState);
_PushState(newState, continuePlaying);
NotifyPlayModeChanged(mode);
}
void
PlaybackManager::SetLoopMode(int32 mode, bool continuePlaying)
{
PlayingState* newState = new PlayingState(*_LastState());
newState->loop_mode = mode;
if (!continuePlaying && !(_PlayingDirectionFor(newState) == 0))
newState->current_frame = _PlayingStartFrameFor(newState);
_PushState(newState, continuePlaying);
NotifyLoopModeChanged(mode);
}
void
PlaybackManager::SetLoopingEnabled(bool enabled, bool continuePlaying)
{
PlayingState* newState = new PlayingState(*_LastState());
newState->looping_enabled = enabled;
if (!continuePlaying && !(_PlayingDirectionFor(newState) == 0))
newState->current_frame = _PlayingStartFrameFor(newState);
_PushState(newState, continuePlaying);
NotifyLoopingEnabledChanged(enabled);
}
void
PlaybackManager::SetSpeed(float speed)
{
#if SUPPORT_SPEED_CHANGES
SpeedInfo* lastSpeed = _LastSpeedInfo();
if (speed != lastSpeed->set_speed) {
SpeedInfo* info = new SpeedInfo(*lastSpeed);
info->activation_frame = NextFrame();
info->set_speed = speed;
if (_PlayingDirectionFor(_StateAtFrame(info->activation_frame)) != 0)
info->speed = info->set_speed;
else
info->speed = 1.0;
_PushSpeedInfo(info);
}
#endif
}
int64
PlaybackManager::NextFrame() const
{
if (fNoAudio)
return FrameForTime(fCurrentVideoTime - 1) + 1;
return FrameForTime(max((bigtime_t)fCurrentAudioTime,
(bigtime_t)fCurrentVideoTime) - 1) + 1;
}
int64
PlaybackManager::NextPlaylistFrame() const
{
return PlaylistFrameAtFrame(NextFrame());
}
int64
PlaybackManager::FirstPlaybackRangeFrame()
{
PlayingState* state = _StateAtFrame(CurrentFrame());
switch (state->loop_mode) {
case LOOPING_RANGE:
return state->start_frame;
case LOOPING_SELECTION:
return 0;
case LOOPING_VISIBLE:
return state->first_visible_frame;
case LOOPING_ALL:
default:
return 0;
}
}
int64
PlaybackManager::LastPlaybackRangeFrame()
{
PlayingState* state = _StateAtFrame(CurrentFrame());
switch (state->loop_mode) {
case LOOPING_RANGE:
return state->end_frame;
case LOOPING_SELECTION:
return state->frame_count - 1;
case LOOPING_VISIBLE:
return state->last_visible_frame;
case LOOPING_ALL:
default:
return state->frame_count - 1;
}
}
int64
PlaybackManager::StartFrameAtFrame(int64 frame)
{
return _StateAtFrame(frame)->start_frame;
}
int64
PlaybackManager::StartFrameAtTime(bigtime_t time)
{
return _StateAtTime(time)->start_frame;
}
int64
PlaybackManager::EndFrameAtFrame(int64 frame)
{
return _StateAtTime(frame)->end_frame;
}
int64
PlaybackManager::EndFrameAtTime(bigtime_t time)
{
return _StateAtTime(time)->end_frame;
}
int64
PlaybackManager::FrameCountAtFrame(int64 frame)
{
return _StateAtTime(frame)->frame_count;
}
int64
PlaybackManager::FrameCountAtTime(bigtime_t time)
{
return _StateAtTime(time)->frame_count;
}
int32
PlaybackManager::PlayModeAtFrame(int64 frame)
{
return _StateAtTime(frame)->play_mode;
}
int32
PlaybackManager::PlayModeAtTime(bigtime_t time)
{
return _StateAtTime(time)->play_mode;
}
int32
PlaybackManager::LoopModeAtFrame(int64 frame)
{
return _StateAtTime(frame)->loop_mode;
}
int32
PlaybackManager::LoopModeAtTime(bigtime_t time)
{
return _StateAtTime(time)->loop_mode;
}
int64
PlaybackManager::PlaylistFrameAtFrame(int64 frame, int32& playingDirection,
bool& newState) const
{
PlayingState* state = _StateAtFrame(frame);
newState = (state->activation_frame == frame);
playingDirection = _PlayingDirectionFor(state);
int64 result = state->current_frame;
if (playingDirection != 0) {
int64 index = state->range_index
+ (frame - state->activation_frame) * playingDirection;
result = _FrameForRangeFrame(state, index);
}
return result;
}
int64
PlaybackManager::PlaylistFrameAtFrame(int64 frame, int32& playingDirection) const
{
bool newState;
return PlaylistFrameAtFrame(frame, playingDirection, newState);
}
int64
PlaybackManager::PlaylistFrameAtFrame(int64 frame) const
{
bool newState;
int32 playingDirection;
return PlaylistFrameAtFrame(frame, playingDirection, newState);
}
int64
PlaybackManager::NextChangeFrame(int64 startFrame, int64 endFrame) const
{
int32 startIndex = _IndexForFrame(startFrame);
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;
}
bigtime_t
PlaybackManager::NextChangeTime(bigtime_t startTime, bigtime_t endTime) const
{
int32 startIndex = _IndexForTime(startTime);
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;
}
void
PlaybackManager::GetPlaylistFrameInterval(int64 startFrame, int64& endFrame,
int64& xStartFrame, int64& xEndFrame, int32& playingDirection) const
{
endFrame = NextChangeFrame(startFrame, endFrame);
xStartFrame = PlaylistFrameAtFrame(startFrame);
xEndFrame = xStartFrame;
playingDirection = _PlayingDirectionFor(_StateAtFrame(startFrame));
bool endOfInterval = false;
int64 intervalLength = 0;
while (startFrame < endFrame && !endOfInterval) {
intervalLength++;
startFrame++;
xEndFrame += playingDirection;
endOfInterval = (PlaylistFrameAtFrame(startFrame) != xEndFrame);
}
if (xStartFrame > xEndFrame) {
swap(xStartFrame, xEndFrame);
xStartFrame++;
xEndFrame++;
}
}
void
PlaybackManager::GetPlaylistTimeInterval(bigtime_t startTime,
bigtime_t& endTime, bigtime_t& xStartTime, bigtime_t& xEndTime,
float& playingSpeed) const
{
int64 startFrame = FrameForTime(startTime);
int64 endFrame = FrameForTime(endTime) + 1;
#if SUPPORT_SPEED_CHANGES
SpeedInfo* info = _SpeedInfoForFrame(startFrame)->speed;
#endif
int64 xStartFrame;
int64 xEndFrame;
int32 playingDirection;
GetPlaylistFrameInterval(startFrame, endFrame, xStartFrame, xEndFrame,
playingDirection);
bigtime_t endTimeForFrame = TimeForFrame(endFrame);
endTime = min(endTime, endTimeForFrame);
bigtime_t intervalLength = endTime - startTime;
switch (playingDirection) {
case 1:
{
#if SUPPORT_SPEED_CHANGES
xStartTime = PlaylistTimeForFrame(xStartFrame)
+ bigtime_t(double(startTime - TimeForFrame(startFrame))
* info->speed);
xEndTime = xStartTime
+ bigtime_t((double)intervalLength * info->speed);
#else
xStartTime = PlaylistTimeForFrame(xStartFrame)
+ startTime - TimeForFrame(startFrame);
xEndTime = xStartTime + intervalLength;
#endif
break;
}
case -1:
{
#if SUPPORT_SPEED_CHANGES
xEndTime = PlaylistTimeForFrame(xEndFrame)
- bigtime_t(double(startTime - TimeForFrame(startFrame))
* info->speed);
xStartTime = xEndTime
- bigtime_t((double)intervalLength * info->speed);
#else
xEndTime = PlaylistTimeForFrame(xEndFrame)
- startTime + TimeForFrame(startFrame);
xStartTime = xEndTime - intervalLength;
#endif
break;
}
case 0:
default:
xStartTime = PlaylistTimeForFrame(xStartFrame);
xEndTime = xStartTime;
break;
}
#if SUPPORT_SPEED_CHANGES
playingSpeed = (float)playingDirection * info->speed;
#else
playingSpeed = (float)playingDirection;
#endif
}
int64
PlaybackManager::FrameForTime(bigtime_t time) const
{
#if SUPPORT_SPEED_CHANGES
SpeedInfo* info = _SpeedInfoForTime(time);
if (!info) {
fprintf(stderr, "PlaybackManager::FrameForTime() - no SpeedInfo!\n");
return 0;
}
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)
frame++;
return frame;
}
bigtime_t
PlaybackManager::TimeForFrame(int64 frame) const
{
#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;
#else
return (bigtime_t)((double)frame * 1000000.0 / (double)fFrameRate);
#endif
}
int64
PlaybackManager::PlaylistFrameForTime(bigtime_t time) const
{
int64 frame = (int64)((double)time * (double)fFrameRate / 1000000.0);
if (TimeForFrame(frame) > time)
frame--;
else if (TimeForFrame(frame + 1) <= time)
frame++;
return frame;
}
bigtime_t
PlaybackManager::PlaylistTimeForFrame(int64 frame) const
{
return (bigtime_t)((double)frame * 1000000.0 / (double)fFrameRate);
}
void
PlaybackManager::SetCurrentAudioTime(bigtime_t time)
{
TRACE("PlaybackManager::SetCurrentAudioTime(%lld)\n", time);
bigtime_t lastFrameTime = _TimeForLastFrame();
fCurrentAudioTime = time;
bigtime_t newLastFrameTime = _TimeForLastFrame();
if (lastFrameTime != newLastFrameTime) {
if (fPerformanceTimeEvent == NULL) {
bigtime_t eventTime = RealTimeForTime(newLastFrameTime);
fPerformanceTimeEvent = new MessageEvent(eventTime, this);
EventQueue::Default().AddEvent(fPerformanceTimeEvent);
}
_CheckStopPlaying();
}
}
void
PlaybackManager::SetCurrentVideoFrame(int64 frame)
{
SetCurrentVideoTime(TimeForFrame(frame));
}
void
PlaybackManager::SetCurrentVideoTime(bigtime_t time)
{
TRACE("PlaybackManager::SetCurrentVideoTime(%lld)\n", time);
bigtime_t lastFrameTime = _TimeForLastFrame();
fCurrentVideoTime = time;
bigtime_t newLastFrameTime = _TimeForLastFrame();
if (lastFrameTime != newLastFrameTime) {
if (fPerformanceTimeEvent == NULL) {
bigtime_t eventTime = RealTimeForTime(newLastFrameTime);
fPerformanceTimeEvent = new MessageEvent(eventTime, this);
EventQueue::Default().AddEvent(fPerformanceTimeEvent);
}
_CheckStopPlaying();
}
}
void
PlaybackManager::SetPerformanceFrame(int64 frame)
{
SetPerformanceTime(TimeForFrame(frame));
}
void
PlaybackManager::SetPerformanceTime(bigtime_t time)
{
int64 oldCurrentFrame = CurrentFrame();
fPerformanceTime = time;
_UpdateStates();
_UpdateSpeedInfos();
int64 currentFrame = CurrentFrame();
if (currentFrame != oldCurrentFrame)
NotifyCurrentFrameChanged(currentFrame);
}
void
PlaybackManager::AddListener(PlaybackListener* listener)
{
if (!listener)
return;
if (!Lock())
return;
if (!fListeners.HasItem(listener) && fListeners.AddItem(listener)) {
if (_LastState()) {
listener->PlayModeChanged(PlayMode());
listener->LoopModeChanged(LoopMode());
listener->LoopingEnabledChanged(IsLoopingEnabled());
listener->VideoBoundsChanged(VideoBounds());
listener->FramesPerSecondChanged(FramesPerSecond());
listener->SpeedChanged(Speed());
listener->CurrentFrameChanged(CurrentFrame());
}
}
Unlock();
}
void
PlaybackManager::RemoveListener(PlaybackListener* listener)
{
if (listener && Lock()) {
fListeners.RemoveItem(listener);
Unlock();
}
}
void
PlaybackManager::NotifyPlayModeChanged(int32 mode) const
{
for (int32 i = 0;
PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
i++) {
listener->PlayModeChanged(mode);
}
}
void
PlaybackManager::NotifyLoopModeChanged(int32 mode) const
{
for (int32 i = 0;
PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
i++) {
listener->LoopModeChanged(mode);
}
}
void
PlaybackManager::NotifyLoopingEnabledChanged(bool enabled) const
{
for (int32 i = 0;
PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
i++) {
listener->LoopingEnabledChanged(enabled);
}
}
void
PlaybackManager::NotifyVideoBoundsChanged(BRect bounds) const
{
for (int32 i = 0;
PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
i++) {
listener->VideoBoundsChanged(bounds);
}
}
void
PlaybackManager::NotifyFPSChanged(float fps) const
{
for (int32 i = 0;
PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
i++) {
listener->FramesPerSecondChanged(fps);
}
}
void
PlaybackManager::NotifyCurrentFrameChanged(int64 frame) const
{
for (int32 i = 0;
PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
i++) {
listener->CurrentFrameChanged(frame);
}
}
void
PlaybackManager::NotifySpeedChanged(float speed) const
{
for (int32 i = 0;
PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
i++) {
listener->SpeedChanged(speed);
}
}
void
PlaybackManager::NotifyFrameDropped() const
{
for (int32 i = 0;
PlaybackListener* listener = (PlaybackListener*)fListeners.ItemAt(i);
i++) {
listener->FrameDropped();
}
}
void
PlaybackManager::NotifyStopFrameReached() const
{
}
void
PlaybackManager::NotifySeekHandled(int64 frame) const
{
}
void
PlaybackManager::PrintState(PlayingState* state)
{
TRACE("state: activation frame: %lld, current frame: %lld, "
"start frame: %lld, end frame: %lld, frame count: %lld, "
"first visible: %lld, last visible: %lld, selection (...), "
"play mode: %ld, loop mode: %ld\n",
state->activation_frame,
state->current_frame,
state->start_frame,
state->end_frame,
state->frame_count,
state->first_visible_frame,
state->last_visible_frame,
state->play_mode,
state->loop_mode);
}
void
PlaybackManager::PrintStateAtFrame(int64 frame)
{
TRACE("frame %lld: ", frame);
PrintState(_StateAtFrame(frame));
}
void
PlaybackManager::_PushState(PlayingState* state, bool adjustCurrentFrame)
{
TRACE("PlaybackManager::_PushState()\n");
if (state == NULL)
return;
int64 oldStopPlayingFrame = fStopPlayingFrame;
fStopPlayingFrame = -1;
PlayingState* lastState = _LastState();
int64 activationFrame = max(max(state->activation_frame,
lastState->activation_frame),
NextFrame());
int64 currentFrame = 0;
if (adjustCurrentFrame) {
currentFrame = PlaylistFrameAtFrame(activationFrame);
if (currentFrame == CurrentFrame()) {
currentFrame++;
}
}
TRACE(" state activation frame: %lld, last state activation frame: %lld, "
"NextFrame(): %lld, currentFrame: %lld, next currentFrame: %lld\n",
state->activation_frame, lastState->activation_frame, NextFrame(),
CurrentFrame(), currentFrame);
if (lastState->activation_frame >= NextFrame()) {
fStates.RemoveItem(fStates.CountItems() - 1);
TRACE("deleting last \n");
PrintState(lastState);
_NotifySeekHandledIfNecessary(lastState);
delete lastState;
} else {
}
if (adjustCurrentFrame)
state->current_frame = currentFrame;
int32 playingDirection = _PlayingDirectionFor(state);
if (playingDirection != 0) {
state->current_frame
= _NextFrameInRange(state, state->current_frame);
} else {
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());
#if SUPPORT_SPEED_CHANGES
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);
#endif
if (playingDirection != 0 && !state->looping_enabled) {
int64 startFrame, endFrame, frameCount;
_GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
if (playingDirection == -1)
swap(startFrame, endFrame);
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) {
fStopPlayingFrame = state->activation_frame
+ frameCount - state->range_index - 1;
} else {
fStopPlayingFrame = state->activation_frame
+ state->range_index;
}
_CheckStopPlaying();
}
TRACE("PlaybackManager::_PushState() done\n");
}
void
PlaybackManager::_UpdateStates()
{
int32 firstActive = _IndexForTime(fPerformanceTime);
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());
}
_NotifySeekHandledIfNecessary(_StateAt(0));
}
int32
PlaybackManager::_IndexForFrame(int64 frame) const
{
int32 index = 0;
PlayingState* state;
while (((state = _StateAt(index + 1))) && state->activation_frame <= frame)
index++;
return index;
}
int32
PlaybackManager::_IndexForTime(bigtime_t time) const
{
return _IndexForFrame(FrameForTime(time));
}
PlaybackManager::PlayingState*
PlaybackManager::_LastState() const
{
return _StateAt(fStates.CountItems() - 1);
}
PlaybackManager::PlayingState*
PlaybackManager::_StateAt(int32 index) const
{
return (PlayingState*)fStates.ItemAt(index);
}
PlaybackManager::PlayingState*
PlaybackManager::_StateAtFrame(int64 frame) const
{
return _StateAt(_IndexForFrame(frame));
}
PlaybackManager::PlayingState*
PlaybackManager::_StateAtTime(bigtime_t time) const
{
return _StateAt(_IndexForTime(time));
}
int32
PlaybackManager::_PlayingDirectionFor(int32 playingMode)
{
int32 direction = 0;
switch (playingMode) {
case MODE_PLAYING_FORWARD:
direction = 1;
break;
case MODE_PLAYING_BACKWARD:
direction = -1;
break;
case MODE_PLAYING_PAUSED_FORWARD:
case MODE_PLAYING_PAUSED_BACKWARD:
break;
}
return direction;
}
int32
PlaybackManager::_PlayingDirectionFor(PlayingState* state)
{
return _PlayingDirectionFor(state->play_mode);
}
void
PlaybackManager::_GetPlayingBoundsFor(PlayingState* state, int64& startFrame,
int64& endFrame, int64& frameCount)
{
switch (state->loop_mode) {
case LOOPING_ALL:
startFrame = 0;
endFrame = max(startFrame, state->frame_count - 1);
frameCount = endFrame - startFrame + 1;
break;
case LOOPING_RANGE:
startFrame = state->start_frame;
endFrame = state->end_frame;
frameCount = endFrame - startFrame + 1;
break;
case LOOPING_VISIBLE:
startFrame = state->first_visible_frame;
endFrame = state->last_visible_frame;
frameCount = endFrame - startFrame + 1;
break;
}
}
int64
PlaybackManager::_PlayingStartFrameFor(PlayingState* state)
{
int64 startFrame, endFrame, frameCount, frame = 0;
_GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
switch (_PlayingDirectionFor(state)) {
case -1:
frame = endFrame;
break;
case 1:
frame = startFrame;
break;
default:
frame = state->current_frame;
break;
}
return frame;
}
int64
PlaybackManager::_PlayingEndFrameFor(PlayingState* state)
{
int64 startFrame, endFrame, frameCount, frame = 0;
_GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
switch (_PlayingDirectionFor(state)) {
case -1:
frame = startFrame;
break;
case 1:
frame = endFrame;
break;
default:
frame = state->current_frame;
break;
}
return frame;
}
int64
PlaybackManager::_RangeFrameForFrame(PlayingState* state, int64 frame)
{
TRACE("PlaybackManager::_RangeFrameForFrame(%lld)\n", frame);
int64 startFrame, endFrame, frameCount;
int64 index = 0;
_GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
TRACE(" start frame: %lld, end frame: %lld, frame count: %lld\n",
startFrame, endFrame, frameCount);
switch (state->loop_mode) {
case LOOPING_ALL:
case LOOPING_RANGE:
case LOOPING_VISIBLE:
index = frame - startFrame;
break;
}
TRACE("PlaybackManager::_RangeFrameForFrame() done: %lld\n", index);
return index;
}
int64
PlaybackManager::_FrameForRangeFrame(PlayingState* state, int64 index)
{
TRACE("PlaybackManager::_FrameForRangeFrame(%lld)\n", index);
int64 startFrame, endFrame, frameCount;
_GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
TRACE(" frame range: %lld - %lld, count: %lld\n", startFrame, endFrame,
frameCount);
if (frameCount > 1)
index = (index % frameCount + frameCount) % frameCount;
int64 frame = startFrame;
switch (state->loop_mode) {
case LOOPING_ALL:
case LOOPING_RANGE:
case LOOPING_VISIBLE:
frame = startFrame + index;
break;
}
TRACE("PlaybackManager::_FrameForRangeFrame() done: %" PRId64 "\n", frame);
return frame;
}
int64
PlaybackManager::_NextFrameInRange(PlayingState* state, int64 frame)
{
int64 newFrame = frame;
int64 startFrame, endFrame, frameCount;
_GetPlayingBoundsFor(state, startFrame, endFrame, frameCount);
if (frame < startFrame || frame > endFrame)
newFrame = _PlayingStartFrameFor(state);
else {
int64 index = _RangeFrameForFrame(state, frame);
newFrame = _FrameForRangeFrame(state, index);
if (newFrame > frame && _PlayingDirectionFor(state) == -1)
newFrame = _FrameForRangeFrame(state, index - 1);
}
return newFrame;
}
void
PlaybackManager::_PushSpeedInfo(SpeedInfo* info)
{
#if SUPPORT_SPEED_CHANGES
if (info == NULL)
return;
if (SpeedInfo* lastSpeed = _LastSpeedInfo()) {
info->activation_time = TimeForFrame(info->activation_frame);
if (lastSpeed->activation_frame == info->activation_frame) {
fSpeeds.RemoveItem(lastSpeed);
delete lastSpeed;
}
}
fSpeeds.AddItem(info);
#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
}
int32
PlaybackManager::_SpeedInfoIndexForFrame(int64 frame) const
{
int32 index = 0;
#if SUPPORT_SPEED_CHANGES
SpeedInfo* info;
while (((info = _SpeedInfoAt(index + 1)))
&& info->activation_frame <= frame) {
index++;
}
#endif
return index;
}
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) {
index++;
}
#endif
return index;
}
PlaybackManager::SpeedInfo*
PlaybackManager::_SpeedInfoForFrame(int64 frame) const
{
return _SpeedInfoAt(_SpeedInfoIndexForFrame(frame));
}
PlaybackManager::SpeedInfo*
PlaybackManager::_SpeedInfoForTime(bigtime_t time) const
{
return _SpeedInfoAt(_SpeedInfoIndexForTime(time));
}
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);
#endif
}
bigtime_t
PlaybackManager::_TimeForLastFrame() const
{
if (fNoAudio)
return TimeForFrame(FrameForTime(fCurrentVideoTime));
return TimeForFrame(FrameForTime(min((bigtime_t)fCurrentAudioTime,
(bigtime_t)fCurrentVideoTime)));
}
bigtime_t
PlaybackManager::_TimeForNextFrame() const
{
return TimeForFrame(NextFrame());
}
void
PlaybackManager::_CheckStopPlaying()
{
if (fStopPlayingFrame > 0 && fStopPlayingFrame <= NextFrame()) {
StopPlaying();
NotifyStopFrameReached();
}
}
void
PlaybackManager::_NotifySeekHandledIfNecessary(PlayingState* state)
{
if (state->is_seek_request) {
state->is_seek_request = false;
NotifySeekHandled(state->current_frame);
}
}