theoraTexture.h
Engine/source/gfx/video/theoraTexture.h
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