123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #ifndef _THEORATEXTURE_H_
- #define _THEORATEXTURE_H_
- #ifdef TORQUE_OGGTHEORA
- #ifndef _PLATFORM_H_
- #include "platform/platform.h"
- #endif
- #ifndef _GFXTEXTUREHANDLE_H_
- #include "gfx/gfxTextureHandle.h"
- #endif
- #ifndef _ASYNCPACKETQUEUE_H_
- #include "platform/async/asyncPacketQueue.h"
- #endif
- #ifndef _ASYNCBUFFEREDSTREAM_H_
- #include "platform/async/asyncBufferedStream.h"
- #endif
- #ifndef _TIMESOURCE_H_
- #include "core/util/timeSource.h"
- #endif
- #ifndef _THREADSAFEREFCOUNT_H_
- #include "platform/threads/threadSafeRefCount.h"
- #endif
- #ifndef _RAWDATA_H_
- #include "core/util/rawData.h"
- #endif
- #ifndef _SIMOBJECT_H_
- #include "console/simObject.h"
- #endif
- #ifndef _SFXSTREAM_H_
- #include "sfx/sfxStream.h"
- #endif
- #ifndef _OGGTHEORADECODER_H_
- #include "core/ogg/oggTheoraDecoder.h"
- #endif
- #ifndef _TYPETRAITS_H_
- #include "platform/typetraits.h"
- #endif
- class SFXDescription;
- class SFXSound;
- class SFXVorbisStream;
- class OggInputStream;
- class OggVorbisDecoder;
- class Stream;
- /// A single frame in the video frame stream.
- ///
- /// Frames are uploaded directly into textures by the asynchronous
- /// streaming system. This offloads as much work as possible to the worker
- /// threads and guarantees the smoothest possible playback.
- ///
- /// Frame records are re-used and are managed directly by the video frame
- /// stream. The number of textures concurrently used by a Theora stream
- /// is determined by its stream read-ahead.
- class TheoraTextureFrame
- {
- public:
-
- typedef void Parent;
-
- /// The texture containing the video frame.
- GFXTexHandle mTexture;
-
- /// The locked rectangle, if the texture is currently locked.
- /// Frames will remain in locked state except if currently displayed.
- GFXLockedRect* mLockedRect;
-
- ///
- U32 mFrameNumber;
-
- /// The play time in seconds at which to display this frame.
- F32 mFrameTime;
-
- /// The duration in seconds to display this frame.
- F32 mFrameDuration;
-
- TheoraTextureFrame()
- : mLockedRect( NULL ), mFrameNumber(0), mFrameTime(0.0f), mFrameDuration(0.0f)
- {
- }
- };
- inline void destructSingle( TheoraTextureFrame* frame )
- {
- // Do nothing.
- }
- /// TheoraTexture decodes Ogg Theora files, and their audio.
- ///
- /// TheoraTexture objects can be used similarly to TextureObjects. Just
- /// set the video, call play(), and then refresh every frame to get the
- /// latest video. Audio happens automagically.
- ///
- /// @note Uses Theora and ogg libraries which are Copyright (C) Xiph.org Foundation
- class TheoraTexture : private IOutputStream< TheoraTextureFrame* >,
- public IPositionable< U32 >
- {
- public:
-
- typedef void Parent;
-
- protected:
-
- typedef IPositionable< U32 > TimeSourceType;
- typedef GenericTimeSource<> TimerType;
- typedef AsyncPacketQueue< TheoraTextureFrame*, TimeSourceType*, IOutputStream< TheoraTextureFrame* >*, F32 > PlaybackQueueType;
-
- class FrameStream;
- class AsyncState;
- friend class GuiTheoraCtrl; // accesses OggTheoraDecoder to set transcoder
-
- /// Parameters for tuning streaming behavior.
- enum
- {
- /// Number of textures to load in background.
- FRAME_READ_AHEAD = 6,
- };
-
- /// WorkItem that reads a frame from a Theora decoder and uploads it into a TheoraTextureFrame.
- ///
- /// Loading directly into textures moves the costly uploads out of the main thread into worker
- /// threads. The downside to this is that since we cannot do GFX work on the worker threads,
- /// we need to expect textures to get to us in locked state.
- class FrameReadItem : public ThreadWorkItem
- {
- public:
-
- typedef ThreadWorkItem Parent;
-
- protected:
-
- /// The asynchronous state we belong to. This reference
- /// ensures that all our streaming state stays live for as long as our
- /// work item is in the pipeline.
- ThreadSafeRef< AsyncState > mAsyncState;
-
- ///
- FrameStream* mFrameStream;
-
- /// The frame texture we are loading.
- TheoraTextureFrame* mFrame;
-
- // WorkItem.
- virtual void execute();
-
- public:
-
- ///
- FrameReadItem( AsyncBufferedInputStream< TheoraTextureFrame*, IInputStream< OggTheoraFrame* >* >* stream,
- ThreadPool::Context* context );
- };
-
- /// Stream filter that turns a stream of OggTheoraFrames into a buffered background stream of TheoraTextureFrame
- /// records.
- ///
- /// This streams allocates a fixed amount 'M' of TheoraTextureFrames. Reading the n-th frame from the stream, will
- /// automatically invalidate the (n-M)-th frame.
- class FrameStream : public AsyncSingleBufferedInputStream< TheoraTextureFrame*, IInputStream< OggTheoraFrame* >*, FrameReadItem >
- {
- public:
-
- typedef AsyncSingleBufferedInputStream< TheoraTextureFrame*, IInputStream< OggTheoraFrame* >*, FrameReadItem > Parent;
-
- protected:
-
- friend class FrameReadItem;
-
- enum
- {
- /// Number of TheoraTextureFrame records to allocate.
- ///
- /// We need to pre-allocate TheoraTextureFrames as we cannot do GFX operations
- /// on the fly on worker threads. This number corresponds to the length of the
- /// buffering queue plus one record that will be returned to the user as the
- /// current frame record.
- NUM_FRAME_RECORDS = FRAME_READ_AHEAD + 1
- };
-
- /// Asynchronous state of the texture object.
- /// This is *NOT* a ThreadSafeRef to not create a cycle.
- AsyncState* mAsyncState;
-
- /// Wrap-around index into "mFrames."
- U32 mFrameIndex;
-
- /// The pre-allocated TheoraTextureFrames.
- TheoraTextureFrame mFrames[ NUM_FRAME_RECORDS ];
-
- public:
-
- ///
- FrameStream( AsyncState* asyncState, bool looping = false );
-
- ///
- void acquireTextureLocks();
-
- ///
- void releaseTextureLocks();
- };
-
- /// Encapsulation of compound asynchronous state. Allows releasing
- /// the entire state in one go.
- class AsyncState : public ThreadSafeRefCount< AsyncState >,
- private IPositionable< U32 >
- {
- public:
-
- typedef void Parent;
- friend class FrameStream; // mDecoderBufferStream
-
- protected:
-
- typedef AsyncSingleBufferedInputStream< OggTheoraFrame* > DecoderBufferStream;
-
- /// Last synchronization position in the video stream. This is what the
- /// Theora decoder gets passed to see if frames are outdated.
- U32 mCurrentTime;
-
- /// The Ogg master stream.
- ThreadSafeRef< OggInputStream > mOggStream;
-
- /// The raw video decoding stream.
- OggTheoraDecoder* mTheoraDecoder;
-
- /// The raw sound decoding stream; NULL if no Vorbis in video or if
- /// Vorbis is streamed separately.
- OggVorbisDecoder* mVorbisDecoder;
-
- /// The background-buffered frame stream.
- ThreadSafeRef< FrameStream > mFrameStream;
-
- public:
-
- ///
- AsyncState( const ThreadSafeRef< OggInputStream >& oggStream, bool looping = false );
-
- /// Return the Theora decoder substream.
- OggTheoraDecoder* getTheora() const { return mTheoraDecoder; }
-
- /// Return the Vorbis decoder substream.
- /// @note If Vorbis streaming is split out into a separate physical substream,
- /// this method will always return NULL even if Vorbis sound is being used.
- OggVorbisDecoder* getVorbis() const { return mVorbisDecoder; }
-
- ///
- const ThreadSafeRef< FrameStream >& getFrameStream() const { return mFrameStream; }
-
- ///
- TheoraTextureFrame* readNextFrame();
-
- ///
- void start();
-
- ///
- void stop();
-
- ///
- bool isAtEnd();
-
- ///
- void syncTime( U32 ms ) { mCurrentTime = ms; }
-
- private:
-
- // IPositionable.
- virtual U32 getPosition() const { return mCurrentTime; }
- virtual void setPosition( U32 pos ) {}
- };
-
- /// The Theora video file.
- String mFilename;
-
- /// The SFXDescription used for sound playback. Synthesized if not provided.
- SimObjectPtr< SFXDescription > mSFXDescription;
-
- /// If there's a Vorbis stream, this is the sound source used for playback.
- /// Playback will synchronize to this source then.
- SimObjectPtr< SFXSound > mSFXSource;
-
- /// The current frame.
- TheoraTextureFrame* mCurrentFrame;
-
- /// The queue that synchronizes the writing of frames to the TheoraTexture.
- PlaybackQueueType* mPlaybackQueue;
-
- /// The timer for synchronizing playback when there is no audio stream
- /// to synchronize to.
- TimerType mPlaybackTimer;
-
- /// Our threaded state.
- ThreadSafeRef< AsyncState > mAsyncState;
-
- ///
- bool mIsPaused;
-
- ///
- U32 mLastFrameNumber;
-
- /// Number of frames we have dropped so far.
- U32 mNumDroppedFrames;
- /// Release all dynamic playback state.
- void _reset();
-
- /// Initialize video playback.
- void _initVideo();
-
- /// Initialize audio playback.
- void _initAudio( const ThreadSafeRef< SFXStream >& stream = NULL );
-
- /// Return the Theora decoder stream or NULL.
- OggTheoraDecoder* _getTheora() const { return ( mAsyncState != NULL ? mAsyncState->getTheora() : NULL ); }
-
- /// Return the Vorbis decoder stream or NULL.
- OggVorbisDecoder* _getVorbis() const { return ( mAsyncState != NULL ? mAsyncState->getVorbis() : NULL ); }
-
- /// Return the object that is acting as our time source.
- TimeSourceType* _getTimeSource() const;
-
- ///
- void _onTextureEvent( GFXTexCallbackCode code );
-
- // IOutputStream.
- virtual void write( TheoraTextureFrame* const* frames, U32 num );
- public:
-
- ///
- TheoraTexture();
-
- ~TheoraTexture();
- /// Return the width of a single video frame in pixels.
- U32 getWidth() const;
-
- /// Return the height of a single video frame in pixels.
- U32 getHeight() const;
-
- /// Return the filename of the Theora video file loaded by the player.
- const String& getFilename() const { return mFilename; }
- /// Load the given Theora video file. Set up audio using the given SFXDescription (must have
- /// streaming enabled). If no SFXDescription is provided, a default description is used.
- bool setFile( const String& filename, SFXDescription* desc = NULL );
-
- /// Start video playback.
- void play();
-
- /// Pause video playback.
- void pause();
-
- /// Stop video playback.
- void stop();
-
- /// Refresh the current frame. This should be called before getTexture() to ensure that
- /// the texture returned by getTexture() contains up-to-date contents.
- void refresh();
-
- /// Return true if a video file has been loaded and is ready for playback.
- bool isReady() const { return ( mAsyncState != NULL ); }
-
- /// Return true if the video is currently playing.
- bool isPlaying() const;
-
- /// Return true if the video is currently paused.
- bool isPaused() const { return mIsPaused; }
-
- /// Return the sequence number of the current frame. Starts at 0.
- U32 getFrameNumber() const { return mCurrentFrame->mFrameNumber; }
-
- /// Return the playback position of the current frame.
- F32 getFrameTime() const { return mCurrentFrame->mFrameTime; }
-
- /// Return the number of frames that have been dropped so far.
- U32 getNumDroppedFrames() const { return mNumDroppedFrames; }
-
- /// Return the texture containing the current frame. Call refresh() first
- /// to ensure the texture contents are up-to-date.
- const GFXTexHandle& getTexture() const { return mCurrentFrame->mTexture; }
- GFXTexHandle& getTexture() { return mCurrentFrame->mTexture; }
-
- // IPositionable.
- virtual U32 getPosition() const { return _getTimeSource()->getPosition(); }
- virtual void setPosition( U32 pos ) {} // Not (yet?) implemented.
- };
- #endif // TORQUE_OGGTHEORA
- #endif // !_THEORATEXTURE_H_
|