Torque3D Documentation / _generateds / guiTheoraCtrl.cpp

guiTheoraCtrl.cpp

Engine/source/gui/theora/guiTheoraCtrl.cpp

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#ifdef TORQUE_OGGTHEORA
 25
 26#include "gui/core/guiControl.h"
 27#include "gui/theora/guiTheoraCtrl.h"
 28#include "console/consoleTypes.h"
 29#include "gfx/gfxDevice.h"
 30#include "gfx/gfxDrawUtil.h"
 31#include "console/engineAPI.h"
 32
 33
 34IMPLEMENT_CONOBJECT( GuiTheoraCtrl );
 35
 36ConsoleDocClass( GuiTheoraCtrl,
 37   "@brief A control to playing Theora videos.\n\n"
 38   
 39   "This control can be used to play videos in the Theora video format.  The videos may include audio in Vorbis format.  The "
 40   "codecs for both formats are integrated with the engine and no codecs must be present on the user's machine.\n\n"
 41   
 42   "@tsexample\n"
 43   "%video = new GuiTheoraCtrl()\n"
 44   "{\n"
 45   "   theoraFile = \"videos/intro.ogv\";\n"
 46   "   playOnWake = false;\n"
 47   "   stopOnSleep = true;\n"
 48   "}\n"
 49   "\n"
 50   "Canvas.setContent( %video );\n"
 51   "%video.play();\n"
 52   "@endtsexample\n\n"
 53   
 54   "@see http://www.theora.org\n\n"
 55   "@ingroup GuiImages"
 56);
 57
 58ImplementEnumType( GuiTheoraTranscoder,
 59   "Routine to use for converting Theora's Y'CbCr pixel format to RGB color space.\n\n"
 60   "@ingroup GuiImages" )
 61   { OggTheoraDecoder::TRANSCODER_Auto, "Auto", "Automatically detect most appropriate setting." },
 62   { OggTheoraDecoder::TRANSCODER_Generic, "Generic", "Slower but beneric transcoder that can convert all Y'CbCr input formats to RGB or RGBA output." },
 63   { OggTheoraDecoder::TRANSCODER_SSE2420RGBA, "SSE2420RGBA", "Fast SSE2-based transcoder with fixed conversion from 4:2:0 Y'CbCr to RGBA." },
 64EndImplementEnumType;
 65
 66//-----------------------------------------------------------------------------
 67
 68GuiTheoraCtrl::GuiTheoraCtrl()
 69{
 70   mFilename         = StringTable->EmptyString();
 71   mDone             = false;
 72   mStopOnSleep      = false;
 73   mMatchVideoSize   = true;
 74   mPlayOnWake       = true;
 75   mRenderDebugInfo  = false;
 76   mTranscoder       = OggTheoraDecoder::TRANSCODER_Auto;
 77   mLoop             = false;
 78   
 79   mBackgroundColor.set( 0, 0, 0, 255);
 80}
 81
 82//-----------------------------------------------------------------------------
 83
 84void GuiTheoraCtrl::initPersistFields()
 85{
 86   addGroup( "Playback");
 87
 88      addField( "theoraFile",       TypeStringFilename,  Offset( mFilename,         GuiTheoraCtrl ),
 89         "Theora video file to play." );
 90      addField( "backgroundColor",  TypeColorI,          Offset( mBackgroundColor,  GuiTheoraCtrl ),
 91         "Fill color when video is not playing." );
 92      addField( "playOnWake",       TypeBool,            Offset( mPlayOnWake,       GuiTheoraCtrl ),
 93         "Whether to start playing video when control is woken up." );
 94      addField( "loop",             TypeBool,            Offset( mLoop,            GuiTheoraCtrl ),
 95         "Loop playback." );
 96      addField( "stopOnSleep",      TypeBool,            Offset( mStopOnSleep,      GuiTheoraCtrl ),
 97         "Whether to stop video when control is set to sleep.\n\n"
 98         "If this is not set to true, the video will be paused when the control is put to sleep.  This is because there is no support "
 99         "for seeking in the video stream in the player backend and letting the time source used to synchronize video (either audio "
100         "or a raw timer) get far ahead of frame decoding will cause possibly very long delays when the control is woken up again." );
101      addField( "matchVideoSize",   TypeBool,            Offset( mMatchVideoSize,   GuiTheoraCtrl ),
102         "Whether to automatically match control extents to the video size." );
103      addField( "renderDebugInfo",  TypeBool,            Offset( mRenderDebugInfo,  GuiTheoraCtrl ),
104         "If true, displays an overlay on top of the video with useful debugging information." );
105      addField( "transcoder",       TYPEID< OggTheoraDecoder::ETranscoder >(), Offset( mTranscoder,       GuiTheoraCtrl ),
106         "The routine to use for Y'CbCr to RGB conversion." );
107
108   endGroup( "Playback" );
109
110   Parent::initPersistFields();
111}
112
113//-----------------------------------------------------------------------------
114
115void GuiTheoraCtrl::setFile( const String& filename )
116{
117   mDone = false;
118   mFilename = filename;
119   mTheoraTexture.setFile( filename );
120   
121   if( mMatchVideoSize && mTheoraTexture.isReady() )
122      setExtent( Point2I( mTheoraTexture.getWidth(), mTheoraTexture.getHeight() ) );
123
124   OggTheoraDecoder* decoder = mTheoraTexture._getTheora();
125   if( decoder != NULL )
126      decoder->setTranscoder( mTranscoder );
127}
128
129//-----------------------------------------------------------------------------
130
131void GuiTheoraCtrl::play()
132{
133   if( mFilename.isEmpty() )
134      return;
135   
136   if( !mTheoraTexture.isPlaying() )
137   {
138      mDone = false;
139      mTheoraTexture.play();
140   }
141}
142
143//-----------------------------------------------------------------------------
144
145void GuiTheoraCtrl::pause()
146{
147   if( !mTheoraTexture.isPlaying() )
148   {
149      Con::errorf( "GuiTheoraCtrl::pause - not playing" );
150      return;
151   }
152   
153   mTheoraTexture.pause();
154}
155
156//-----------------------------------------------------------------------------
157
158void GuiTheoraCtrl::stop()
159{
160   mTheoraTexture.stop();
161   mDone = true;
162}
163
164//-----------------------------------------------------------------------------
165
166bool GuiTheoraCtrl::onWake()
167{
168   if( !Parent::onWake() )
169      return false;
170
171   if( !mTheoraTexture.isReady() )
172      setFile( mFilename );
173   
174   if( mPlayOnWake && !mTheoraTexture.isPlaying() )
175      play();
176
177   return true;
178}
179
180//-----------------------------------------------------------------------------
181
182void GuiTheoraCtrl::onSleep()
183{
184   Parent::onSleep();
185
186   if( mTheoraTexture.isPlaying() )
187   {
188      if( mStopOnSleep )
189         stop();
190      else
191         pause();
192   }
193}
194
195//-----------------------------------------------------------------------------
196
197void GuiTheoraCtrl::onRender(Point2I offset, const RectI &updateRect)
198{
199   const RectI rect(offset, getBounds().extent);
200
201   if( mTheoraTexture.isReady() )
202   {
203      mTheoraTexture.refresh();
204      if( mTheoraTexture.isPlaying()
205          || mTheoraTexture.isPaused() )
206      {
207         // Draw the frame.
208         
209         GFXDrawUtil* drawUtil = GFX->getDrawUtil();
210         drawUtil->clearBitmapModulation();
211         drawUtil->drawBitmapStretch( mTheoraTexture.getTexture(), rect );
212         
213         // Draw frame info, if requested.
214         
215         if( mRenderDebugInfo )
216         {
217            String info = String::ToString( "Frame Number: %i | Frame Time: %.2fs | Playback Time: %.2fs | Dropped: %i",
218               mTheoraTexture.getFrameNumber(),
219               mTheoraTexture.getFrameTime(),
220               F32( mTheoraTexture.getPosition() ) / 1000.f,
221               mTheoraTexture.getNumDroppedFrames() );
222            
223            drawUtil->setBitmapModulation( mProfile->mFontColors[ 0 ] );
224            drawUtil->drawText( mProfile->mFont, localToGlobalCoord( Point2I( 0, 0 ) ), info, mProfile->mFontColors );
225         }
226      }
227      else
228      {
229         if(mLoop)
230         {
231            play();
232         } else {
233            mDone = true;
234         }
235      }
236   }
237   else
238      GFX->getDrawUtil()->drawRectFill(rect, mBackgroundColor); // black rect
239
240   renderChildControls(offset, updateRect);
241}
242
243//-----------------------------------------------------------------------------
244
245void GuiTheoraCtrl::inspectPostApply()
246{
247   if( !mTheoraTexture.getFilename().equal( mFilename, String::NoCase ) )
248   {
249      stop();
250      setFile( mFilename );
251      
252      if( mPlayOnWake && !mTheoraTexture.isPlaying() )
253         play();
254   }
255   
256   if( mMatchVideoSize && mTheoraTexture.isReady() )
257      setExtent( Point2I( mTheoraTexture.getWidth(), mTheoraTexture.getHeight() ) );
258
259   OggTheoraDecoder* decoder = mTheoraTexture._getTheora();
260   if( decoder != NULL )
261      decoder->setTranscoder( mTranscoder );
262      
263   Parent::inspectPostApply();
264}
265
266//=============================================================================
267//    API.
268//=============================================================================
269// MARK: ---- API ----
270
271//-----------------------------------------------------------------------------
272
273DefineEngineMethod( GuiTheoraCtrl, setFile, void, ( const char* filename ),,
274   "Set the video file to play.  If a video is already playing, playback is stopped and "
275   "the new video file is loaded.\n\n"
276   "@param filename The video file to load." )
277{
278   object->setFile( filename );
279}
280
281//-----------------------------------------------------------------------------
282
283DefineEngineMethod( GuiTheoraCtrl, play, void, (),,
284   "Start playing the video.  If the video is already playing, the call is ignored." )
285{
286   object->play();
287}
288
289//-----------------------------------------------------------------------------
290
291DefineEngineMethod( GuiTheoraCtrl, pause, void, (),,
292   "Pause playback of the video.  If the video is not currently playing, the call is ignored.\n\n"
293   "While stopped, the control displays the last frame." )
294{
295   object->pause();
296}
297
298//-----------------------------------------------------------------------------
299
300DefineEngineMethod( GuiTheoraCtrl, stop, void, (),,
301   "Stop playback of the video.  The next call to play() will then start playback from the beginning of the video.\n\n"
302   "While stopped, the control renders empty with just the background color." )
303{
304   object->stop();
305}
306
307//-----------------------------------------------------------------------------
308
309DefineEngineMethod( GuiTheoraCtrl, getCurrentTime, F32, (),,
310   "Get the current playback time.\n\n"
311   "@return The elapsed playback time in seconds." )
312{
313   return object->getCurrentTime();
314}
315
316//-----------------------------------------------------------------------------
317
318DefineEngineMethod( GuiTheoraCtrl, isPlaybackDone, bool, (),,
319   "Test whether the video has finished playing.\n\n"
320   "@return True if the video has finished playing, false otherwise." )
321{
322   return object->isPlaybackDone();
323}
324
325#endif // TORQUE_OGGTHEORA
326