guiTheoraCtrl.cpp
Engine/source/gui/theora/guiTheoraCtrl.cpp
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