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. void execute() override;
  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. virtual ~AsyncState() {};
  209. /// Return the Theora decoder substream.
  210. OggTheoraDecoder* getTheora() const { return mTheoraDecoder; }
  211. /// Return the Vorbis decoder substream.
  212. /// @note If Vorbis streaming is split out into a separate physical substream,
  213. /// this method will always return NULL even if Vorbis sound is being used.
  214. OggVorbisDecoder* getVorbis() const { return mVorbisDecoder; }
  215. ///
  216. const ThreadSafeRef< FrameStream >& getFrameStream() const { return mFrameStream; }
  217. ///
  218. TheoraTextureFrame* readNextFrame();
  219. ///
  220. void start();
  221. ///
  222. void stop();
  223. ///
  224. bool isAtEnd();
  225. ///
  226. void syncTime( U32 ms ) { mCurrentTime = ms; }
  227. private:
  228. // IPositionable.
  229. U32 getPosition() const override { return mCurrentTime; }
  230. void setPosition( U32 pos ) override {}
  231. };
  232. /// The Theora video file.
  233. String mFilename;
  234. /// The SFXDescription used for sound playback. Synthesized if not provided.
  235. SimObjectPtr< SFXDescription > mSFXDescription;
  236. /// If there's a Vorbis stream, this is the sound source used for playback.
  237. /// Playback will synchronize to this source then.
  238. SimObjectPtr< SFXSound > mSFXSource;
  239. /// The current frame.
  240. TheoraTextureFrame* mCurrentFrame;
  241. /// The queue that synchronizes the writing of frames to the TheoraTexture.
  242. PlaybackQueueType* mPlaybackQueue;
  243. /// The timer for synchronizing playback when there is no audio stream
  244. /// to synchronize to.
  245. TimerType mPlaybackTimer;
  246. /// Our threaded state.
  247. ThreadSafeRef< AsyncState > mAsyncState;
  248. ///
  249. bool mIsPaused;
  250. ///
  251. U32 mLastFrameNumber;
  252. /// Number of frames we have dropped so far.
  253. U32 mNumDroppedFrames;
  254. /// Release all dynamic playback state.
  255. void _reset();
  256. /// Initialize video playback.
  257. void _initVideo();
  258. /// Initialize audio playback.
  259. void _initAudio( const ThreadSafeRef< SFXStream >& stream = NULL );
  260. /// Return the Theora decoder stream or NULL.
  261. OggTheoraDecoder* _getTheora() const { return ( mAsyncState != NULL ? mAsyncState->getTheora() : NULL ); }
  262. /// Return the Vorbis decoder stream or NULL.
  263. OggVorbisDecoder* _getVorbis() const { return ( mAsyncState != NULL ? mAsyncState->getVorbis() : NULL ); }
  264. /// Return the object that is acting as our time source.
  265. TimeSourceType* _getTimeSource() const;
  266. ///
  267. void _onTextureEvent( GFXTexCallbackCode code );
  268. // IOutputStream.
  269. void write( TheoraTextureFrame* const* frames, U32 num ) override;
  270. public:
  271. ///
  272. TheoraTexture();
  273. ~TheoraTexture();
  274. /// Return the width of a single video frame in pixels.
  275. U32 getWidth() const;
  276. /// Return the height of a single video frame in pixels.
  277. U32 getHeight() const;
  278. /// Return the filename of the Theora video file loaded by the player.
  279. const String& getFilename() const { return mFilename; }
  280. /// Load the given Theora video file. Set up audio using the given SFXDescription (must have
  281. /// streaming enabled). If no SFXDescription is provided, a default description is used.
  282. bool setFile( const String& filename, SFXDescription* desc = NULL );
  283. /// Start video playback.
  284. void play();
  285. /// Pause video playback.
  286. void pause();
  287. /// Stop video playback.
  288. void stop();
  289. /// Refresh the current frame. This should be called before getTexture() to ensure that
  290. /// the texture returned by getTexture() contains up-to-date contents.
  291. void refresh();
  292. /// Return true if a video file has been loaded and is ready for playback.
  293. bool isReady() const { return ( mAsyncState != NULL ); }
  294. /// Return true if the video is currently playing.
  295. bool isPlaying() const;
  296. /// Return true if the video is currently paused.
  297. bool isPaused() const { return mIsPaused; }
  298. /// Return the sequence number of the current frame. Starts at 0.
  299. U32 getFrameNumber() const { return mCurrentFrame->mFrameNumber; }
  300. /// Return the playback position of the current frame.
  301. F32 getFrameTime() const { return mCurrentFrame->mFrameTime; }
  302. /// Return the number of frames that have been dropped so far.
  303. U32 getNumDroppedFrames() const { return mNumDroppedFrames; }
  304. /// Return the texture containing the current frame. Call refresh() first
  305. /// to ensure the texture contents are up-to-date.
  306. const GFXTexHandle& getTexture() const { return mCurrentFrame->mTexture; }
  307. GFXTexHandle& getTexture() { return mCurrentFrame->mTexture; }
  308. // IPositionable.
  309. U32 getPosition() const override { return _getTimeSource()->getPosition(); }
  310. void setPosition( U32 pos ) override {} // Not (yet?) implemented.
  311. };
  312. #endif // TORQUE_OGGTHEORA
  313. #endif // !_THEORATEXTURE_H_