theoraTexture.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _THEORATEXTURE_H_
  23. #define _THEORATEXTURE_H_
  24. #ifdef TORQUE_OGGTHEORA
  25. #ifndef _PLATFORM_H_
  26. #include "platform/platform.h"
  27. #endif
  28. #ifndef _GFXTEXTUREHANDLE_H_
  29. #include "gfx/gfxTextureHandle.h"
  30. #endif
  31. #ifndef _ASYNCPACKETQUEUE_H_
  32. #include "platform/async/asyncPacketQueue.h"
  33. #endif
  34. #ifndef _ASYNCBUFFEREDSTREAM_H_
  35. #include "platform/async/asyncBufferedStream.h"
  36. #endif
  37. #ifndef _TIMESOURCE_H_
  38. #include "core/util/timeSource.h"
  39. #endif
  40. #ifndef _THREADSAFEREFCOUNT_H_
  41. #include "platform/threads/threadSafeRefCount.h"
  42. #endif
  43. #ifndef _RAWDATA_H_
  44. #include "core/util/rawData.h"
  45. #endif
  46. #ifndef _SIMOBJECT_H_
  47. #include "console/simObject.h"
  48. #endif
  49. #ifndef _SFXSTREAM_H_
  50. #include "sfx/sfxStream.h"
  51. #endif
  52. #ifndef _OGGTHEORADECODER_H_
  53. #include "core/ogg/oggTheoraDecoder.h"
  54. #endif
  55. #ifndef _TYPETRAITS_H_
  56. #include "platform/typetraits.h"
  57. #endif
  58. class SFXDescription;
  59. class SFXSound;
  60. class SFXVorbisStream;
  61. class OggInputStream;
  62. class OggVorbisDecoder;
  63. class Stream;
  64. /// A single frame in the video frame stream.
  65. ///
  66. /// Frames are uploaded directly into textures by the asynchronous
  67. /// streaming system. This offloads as much work as possible to the worker
  68. /// threads and guarantees the smoothest possible playback.
  69. ///
  70. /// Frame records are re-used and are managed directly by the video frame
  71. /// stream. The number of textures concurrently used by a Theora stream
  72. /// is determined by its stream read-ahead.
  73. class TheoraTextureFrame
  74. {
  75. public:
  76. typedef void Parent;
  77. /// The texture containing the video frame.
  78. GFXTexHandle mTexture;
  79. /// The locked rectangle, if the texture is currently locked.
  80. /// Frames will remain in locked state except if currently displayed.
  81. GFXLockedRect* mLockedRect;
  82. ///
  83. U32 mFrameNumber;
  84. /// The play time in seconds at which to display this frame.
  85. F32 mFrameTime;
  86. /// The duration in seconds to display this frame.
  87. F32 mFrameDuration;
  88. TheoraTextureFrame()
  89. : mLockedRect( NULL ), mFrameNumber(0), mFrameTime(0.0f), mFrameDuration(0.0f)
  90. {
  91. }
  92. };
  93. inline void destructSingle( TheoraTextureFrame* frame )
  94. {
  95. // Do nothing.
  96. }
  97. /// TheoraTexture decodes Ogg Theora files, and their audio.
  98. ///
  99. /// TheoraTexture objects can be used similarly to TextureObjects. Just
  100. /// set the video, call play(), and then refresh every frame to get the
  101. /// latest video. Audio happens automagically.
  102. ///
  103. /// @note Uses Theora and ogg libraries which are Copyright (C) Xiph.org Foundation
  104. class TheoraTexture : private IOutputStream< TheoraTextureFrame* >,
  105. public IPositionable< U32 >
  106. {
  107. public:
  108. typedef void Parent;
  109. protected:
  110. typedef IPositionable< U32 > TimeSourceType;
  111. typedef GenericTimeSource<> TimerType;
  112. typedef AsyncPacketQueue< TheoraTextureFrame*, TimeSourceType*, IOutputStream< TheoraTextureFrame* >*, F32 > PlaybackQueueType;
  113. class FrameStream;
  114. class AsyncState;
  115. friend class GuiTheoraCtrl; // accesses OggTheoraDecoder to set transcoder
  116. /// Parameters for tuning streaming behavior.
  117. enum
  118. {
  119. /// Number of textures to load in background.
  120. FRAME_READ_AHEAD = 6,
  121. };
  122. /// WorkItem that reads a frame from a Theora decoder and uploads it into a TheoraTextureFrame.
  123. ///
  124. /// Loading directly into textures moves the costly uploads out of the main thread into worker
  125. /// threads. The downside to this is that since we cannot do GFX work on the worker threads,
  126. /// we need to expect textures to get to us in locked state.
  127. class FrameReadItem : public ThreadWorkItem
  128. {
  129. public:
  130. typedef ThreadWorkItem Parent;
  131. protected:
  132. /// The asynchronous state we belong to. This reference
  133. /// ensures that all our streaming state stays live for as long as our
  134. /// work item is in the pipeline.
  135. ThreadSafeRef< AsyncState > mAsyncState;
  136. ///
  137. FrameStream* mFrameStream;
  138. /// The frame texture we are loading.
  139. TheoraTextureFrame* mFrame;
  140. // WorkItem.
  141. virtual void execute();
  142. public:
  143. ///
  144. FrameReadItem( AsyncBufferedInputStream< TheoraTextureFrame*, IInputStream< OggTheoraFrame* >* >* stream,
  145. ThreadPool::Context* context );
  146. };
  147. /// Stream filter that turns a stream of OggTheoraFrames into a buffered background stream of TheoraTextureFrame
  148. /// records.
  149. ///
  150. /// This streams allocates a fixed amount 'M' of TheoraTextureFrames. Reading the n-th frame from the stream, will
  151. /// automatically invalidate the (n-M)-th frame.
  152. class FrameStream : public AsyncSingleBufferedInputStream< TheoraTextureFrame*, IInputStream< OggTheoraFrame* >*, FrameReadItem >
  153. {
  154. public:
  155. typedef AsyncSingleBufferedInputStream< TheoraTextureFrame*, IInputStream< OggTheoraFrame* >*, FrameReadItem > Parent;
  156. protected:
  157. friend class FrameReadItem;
  158. enum
  159. {
  160. /// Number of TheoraTextureFrame records to allocate.
  161. ///
  162. /// We need to pre-allocate TheoraTextureFrames as we cannot do GFX operations
  163. /// on the fly on worker threads. This number corresponds to the length of the
  164. /// buffering queue plus one record that will be returned to the user as the
  165. /// current frame record.
  166. NUM_FRAME_RECORDS = FRAME_READ_AHEAD + 1
  167. };
  168. /// Asynchronous state of the texture object.
  169. /// This is *NOT* a ThreadSafeRef to not create a cycle.
  170. AsyncState* mAsyncState;
  171. /// Wrap-around index into "mFrames."
  172. U32 mFrameIndex;
  173. /// The pre-allocated TheoraTextureFrames.
  174. TheoraTextureFrame mFrames[ NUM_FRAME_RECORDS ];
  175. public:
  176. ///
  177. FrameStream( AsyncState* asyncState, bool looping = false );
  178. ///
  179. void acquireTextureLocks();
  180. ///
  181. void releaseTextureLocks();
  182. };
  183. /// Encapsulation of compound asynchronous state. Allows releasing
  184. /// the entire state in one go.
  185. class AsyncState : public ThreadSafeRefCount< AsyncState >,
  186. private IPositionable< U32 >
  187. {
  188. public:
  189. typedef void Parent;
  190. friend class FrameStream; // mDecoderBufferStream
  191. protected:
  192. typedef AsyncSingleBufferedInputStream< OggTheoraFrame* > DecoderBufferStream;
  193. /// Last synchronization position in the video stream. This is what the
  194. /// Theora decoder gets passed to see if frames are outdated.
  195. U32 mCurrentTime;
  196. /// The Ogg master stream.
  197. ThreadSafeRef< OggInputStream > mOggStream;
  198. /// The raw video decoding stream.
  199. OggTheoraDecoder* mTheoraDecoder;
  200. /// The raw sound decoding stream; NULL if no Vorbis in video or if
  201. /// Vorbis is streamed separately.
  202. OggVorbisDecoder* mVorbisDecoder;
  203. /// The background-buffered frame stream.
  204. ThreadSafeRef< FrameStream > mFrameStream;
  205. public:
  206. ///
  207. AsyncState( const ThreadSafeRef< OggInputStream >& oggStream, bool looping = false );
  208. /// Return the Theora decoder substream.
  209. OggTheoraDecoder* getTheora() const { return mTheoraDecoder; }
  210. /// Return the Vorbis decoder substream.
  211. /// @note If Vorbis streaming is split out into a separate physical substream,
  212. /// this method will always return NULL even if Vorbis sound is being used.
  213. OggVorbisDecoder* getVorbis() const { return mVorbisDecoder; }
  214. ///
  215. const ThreadSafeRef< FrameStream >& getFrameStream() const { return mFrameStream; }
  216. ///
  217. TheoraTextureFrame* readNextFrame();
  218. ///
  219. void start();
  220. ///
  221. void stop();
  222. ///
  223. bool isAtEnd();
  224. ///
  225. void syncTime( U32 ms ) { mCurrentTime = ms; }
  226. private:
  227. // IPositionable.
  228. virtual U32 getPosition() const { return mCurrentTime; }
  229. virtual void setPosition( U32 pos ) {}
  230. };
  231. /// The Theora video file.
  232. String mFilename;
  233. /// The SFXDescription used for sound playback. Synthesized if not provided.
  234. SimObjectPtr< SFXDescription > mSFXDescription;
  235. /// If there's a Vorbis stream, this is the sound source used for playback.
  236. /// Playback will synchronize to this source then.
  237. SimObjectPtr< SFXSound > mSFXSource;
  238. /// The current frame.
  239. TheoraTextureFrame* mCurrentFrame;
  240. /// The queue that synchronizes the writing of frames to the TheoraTexture.
  241. PlaybackQueueType* mPlaybackQueue;
  242. /// The timer for synchronizing playback when there is no audio stream
  243. /// to synchronize to.
  244. TimerType mPlaybackTimer;
  245. /// Our threaded state.
  246. ThreadSafeRef< AsyncState > mAsyncState;
  247. ///
  248. bool mIsPaused;
  249. ///
  250. U32 mLastFrameNumber;
  251. /// Number of frames we have dropped so far.
  252. U32 mNumDroppedFrames;
  253. /// Release all dynamic playback state.
  254. void _reset();
  255. /// Initialize video playback.
  256. void _initVideo();
  257. /// Initialize audio playback.
  258. void _initAudio( const ThreadSafeRef< SFXStream >& stream = NULL );
  259. /// Return the Theora decoder stream or NULL.
  260. OggTheoraDecoder* _getTheora() const { return ( mAsyncState != NULL ? mAsyncState->getTheora() : NULL ); }
  261. /// Return the Vorbis decoder stream or NULL.
  262. OggVorbisDecoder* _getVorbis() const { return ( mAsyncState != NULL ? mAsyncState->getVorbis() : NULL ); }
  263. /// Return the object that is acting as our time source.
  264. TimeSourceType* _getTimeSource() const;
  265. ///
  266. void _onTextureEvent( GFXTexCallbackCode code );
  267. // IOutputStream.
  268. virtual void write( TheoraTextureFrame* const* frames, U32 num );
  269. public:
  270. ///
  271. TheoraTexture();
  272. ~TheoraTexture();
  273. /// Return the width of a single video frame in pixels.
  274. U32 getWidth() const;
  275. /// Return the height of a single video frame in pixels.
  276. U32 getHeight() const;
  277. /// Return the filename of the Theora video file loaded by the player.
  278. const String& getFilename() const { return mFilename; }
  279. /// Load the given Theora video file. Set up audio using the given SFXDescription (must have
  280. /// streaming enabled). If no SFXDescription is provided, a default description is used.
  281. bool setFile( const String& filename, SFXDescription* desc = NULL );
  282. /// Start video playback.
  283. void play();
  284. /// Pause video playback.
  285. void pause();
  286. /// Stop video playback.
  287. void stop();
  288. /// Refresh the current frame. This should be called before getTexture() to ensure that
  289. /// the texture returned by getTexture() contains up-to-date contents.
  290. void refresh();
  291. /// Return true if a video file has been loaded and is ready for playback.
  292. bool isReady() const { return ( mAsyncState != NULL ); }
  293. /// Return true if the video is currently playing.
  294. bool isPlaying() const;
  295. /// Return true if the video is currently paused.
  296. bool isPaused() const { return mIsPaused; }
  297. /// Return the sequence number of the current frame. Starts at 0.
  298. U32 getFrameNumber() const { return mCurrentFrame->mFrameNumber; }
  299. /// Return the playback position of the current frame.
  300. F32 getFrameTime() const { return mCurrentFrame->mFrameTime; }
  301. /// Return the number of frames that have been dropped so far.
  302. U32 getNumDroppedFrames() const { return mNumDroppedFrames; }
  303. /// Return the texture containing the current frame. Call refresh() first
  304. /// to ensure the texture contents are up-to-date.
  305. const GFXTexHandle& getTexture() const { return mCurrentFrame->mTexture; }
  306. GFXTexHandle& getTexture() { return mCurrentFrame->mTexture; }
  307. // IPositionable.
  308. virtual U32 getPosition() const { return _getTimeSource()->getPosition(); }
  309. virtual void setPosition( U32 pos ) {} // Not (yet?) implemented.
  310. };
  311. #endif // TORQUE_OGGTHEORA
  312. #endif // !_THEORATEXTURE_H_