⛏️ index : haiku.git

/*
 * Copyright (c) 2000-2008, Ingo Weinhold <ingo_weinhold@gmx.de>,
 * Copyright (c) 2000-2008, Stephan Aßmus <superstippi@gmx.de>,
 * All Rights Reserved. Distributed under the terms of the MIT license.
 */

/*!	This class controls our playback
	Note: Add/RemoveListener() are the only methods that lock the object
	themselves. All other methods need it to be locked before.
*/
#ifndef PLAYBACK_MANAGER_H
#define PLAYBACK_MANAGER_H


#include <List.h>
#include <Looper.h>
#include <Rect.h>


class MessageEvent;
class PlaybackListener;


enum {
	MODE_PLAYING_FORWARD			= 1,
	MODE_PLAYING_BACKWARD			= 2,
	MODE_PLAYING_PAUSED_FORWARD		= -1,
	MODE_PLAYING_PAUSED_BACKWARD	= -2,
};

enum {
	LOOPING_ALL						= 0,
	LOOPING_RANGE					= 1,
	LOOPING_SELECTION				= 2,
	LOOPING_VISIBLE					= 3,
};

enum {
	MSG_PLAYBACK_FORCE_UPDATE		= 'pbfu',
	MSG_PLAYBACK_SET_RANGE			= 'pbsr',
	MSG_PLAYBACK_SET_VISIBLE		= 'pbsv',
	MSG_PLAYBACK_SET_LOOP_MODE		= 'pbsl',
};


class PlaybackManager : public BLooper {
private:
			struct PlayingState;
			struct SpeedInfo;

public:
								PlaybackManager();
	virtual						~PlaybackManager();

			void				Init(float frameRate,
									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
	virtual	void				MessageReceived(BMessage* message);

			void				StartPlaying(bool atBeginning = false);
			void				StopPlaying();
			void				TogglePlaying(bool atBeginning = false);
			void				PausePlaying();
			bool				IsPlaying() const;

			int32				PlayMode() const;
			int32				LoopMode() const;
			bool				IsLoopingEnabled() const;
			int64				CurrentFrame() const;
			float				Speed() const;

	virtual	void				SetFramesPerSecond(float framesPerSecond);
			float				FramesPerSecond() const;

	virtual	BRect				VideoBounds() const = 0;

	virtual	void				FrameDropped() const;

			void				DurationChanged();
	virtual	int64				Duration() = 0;

	virtual	void				SetVolume(float percent) = 0;

			// playing state manipulation
			void				SetCurrentFrame(int64 frame);
	virtual	void				SetPlayMode(int32 mode,
									bool continuePlaying = true);
			void				SetLoopMode(int32 mode,
									bool continuePlaying = true);
			void				SetLoopingEnabled(bool enabled,
									bool continuePlaying = true);
			void				SetSpeed(float speed);

			// playing state change info
			int64				NextFrame() const;
			int64				NextPlaylistFrame() const;

			int64				FirstPlaybackRangeFrame();
			int64				LastPlaybackRangeFrame();

			// playing state access
			int64				StartFrameAtFrame(int64 frame);
			int64				StartFrameAtTime(bigtime_t time);
			int64				EndFrameAtFrame(int64 frame);
			int64				EndFrameAtTime(bigtime_t time);
			int64				FrameCountAtFrame(int64 frame);
			int64				FrameCountAtTime(bigtime_t time);
			int32				PlayModeAtFrame(int64 frame);
			int32				PlayModeAtTime(bigtime_t time);
			int32				LoopModeAtFrame(int64 frame);
			int32				LoopModeAtTime(bigtime_t time);
			// ...

			// playing frame/time/interval info
			int64				PlaylistFrameAtFrame(int64 frame,
									int32& playingDirection,
									bool& newState) const;
			int64				PlaylistFrameAtFrame(int64 frame,
									int32& playingDirection) const;
			int64				PlaylistFrameAtFrame(int64 frame) const;
			int64				NextChangeFrame(int64 startFrame,
												int64 endFrame) const;
			bigtime_t			NextChangeTime(bigtime_t startTime,
											   bigtime_t endTime) const;
			void				GetPlaylistFrameInterval(
									int64 startFrame, int64& endFrame,
									int64& xStartFrame, int64& xEndFrame,
									int32& playingDirection) const;

	virtual	void				GetPlaylistTimeInterval(
									bigtime_t startTime, bigtime_t& endTime,
									bigtime_t& xStartTime, bigtime_t& xEndTime,
									float& playingSpeed) const;

			// conversion: video frame <-> (performance) time
			int64				FrameForTime(bigtime_t time) const;
			bigtime_t			TimeForFrame(int64 frame) const;
			// conversion: (performance) time <-> real time
	virtual	bigtime_t			RealTimeForTime(bigtime_t time) const = 0;
	virtual	bigtime_t			TimeForRealTime(bigtime_t time) const = 0;
			// conversion: Playist frame <-> Playlist time
			int64				PlaylistFrameForTime(bigtime_t time) const;
			bigtime_t			PlaylistTimeForFrame(int64 frame) const;

			// to be called by audio/video producers
	virtual	void				SetCurrentAudioTime(bigtime_t time);
			void				SetCurrentVideoFrame(int64 frame);
			void				SetCurrentVideoTime(bigtime_t time);
			void				SetPerformanceFrame(int64 frame);
			void				SetPerformanceTime(bigtime_t time);

			// listener support
			void				AddListener(PlaybackListener* listener);
			void				RemoveListener(PlaybackListener* listener);

	virtual	void				NotifyPlayModeChanged(int32 mode) const;
	virtual	void				NotifyLoopModeChanged(int32 mode) const;
	virtual	void				NotifyLoopingEnabledChanged(
									bool enabled) const;
	virtual	void				NotifyVideoBoundsChanged(BRect bounds) const;
	virtual	void				NotifyFPSChanged(float fps) const;
	virtual	void				NotifyCurrentFrameChanged(int64 frame) const;
	virtual	void				NotifySpeedChanged(float speed) const;
	virtual	void				NotifyFrameDropped() const;
	virtual	void				NotifyStopFrameReached() const;
	virtual	void				NotifySeekHandled(int64 seekedFrame) const;

			// debugging
			void				PrintState(PlayingState* state);
			void				PrintStateAtFrame(int64 frame);

 private:
			// state management
			void				_PushState(PlayingState* state,
										   bool adjustCurrentFrame);
			void				_UpdateStates();
			int32				_IndexForFrame(int64 frame) const;
			int32				_IndexForTime(bigtime_t time) const;
			PlayingState*		_LastState() const;
			PlayingState*		_StateAt(int32 index) const;
			PlayingState*		_StateAtTime(bigtime_t time) const;
			PlayingState*		_StateAtFrame(int64 frame) const;

	static	int32				_PlayingDirectionFor(int32 playingMode);
	static	int32				_PlayingDirectionFor(PlayingState* state);
	static	void				_GetPlayingBoundsFor(PlayingState* state,
													 int64& startFrame,
													 int64& endFrame,
													 int64& frameCount);
	static	int64				_PlayingStartFrameFor(PlayingState* state);
	static	int64				_PlayingEndFrameFor(PlayingState* state);
	static	int64				_RangeFrameForFrame(PlayingState* state,
													int64 frame);
	static	int64				_FrameForRangeFrame(PlayingState* state,
													int64 index);
	static	int64				_NextFrameInRange(PlayingState* state,
												  int64 frame);

			// speed management
			void				_PushSpeedInfo(SpeedInfo* info);
			SpeedInfo*			_LastSpeedInfo() const;
			SpeedInfo*			_SpeedInfoAt(int32 index) const;
			int32				_SpeedInfoIndexForFrame(int64 frame) const;
			int32				_SpeedInfoIndexForTime(bigtime_t time) const;
			SpeedInfo*			_SpeedInfoForFrame(int64 frame) const;
			SpeedInfo*			_SpeedInfoForTime(bigtime_t time) const;
			void				_UpdateSpeedInfos();

			bigtime_t			_TimeForLastFrame() const;
			bigtime_t			_TimeForNextFrame() const;

			void				_NotifySeekHandledIfNecessary(
									PlayingState* state);
			void				_CheckStopPlaying();

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:
 			bool				fNoAudio;
};


#endif	// PLAYBACK_MANAGER_H