Torque3D Documentation / _generateds / theoraTexture.h

theoraTexture.h

Engine/source/gfx/video/theoraTexture.h

More...

Detailed Description

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