123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #ifdef TORQUE_OGGTHEORA
- #include "gui/core/guiControl.h"
- #include "gui/theora/guiTheoraCtrl.h"
- #include "console/consoleTypes.h"
- #include "gfx/gfxDevice.h"
- #include "gfx/gfxDrawUtil.h"
- #include "console/engineAPI.h"
- IMPLEMENT_CONOBJECT( GuiTheoraCtrl );
- ConsoleDocClass( GuiTheoraCtrl,
- "@brief A control to playing Theora videos.\n\n"
-
- "This control can be used to play videos in the Theora video format. The videos may include audio in Vorbis format. The "
- "codecs for both formats are integrated with the engine and no codecs must be present on the user's machine.\n\n"
-
- "@tsexample\n"
- "%video = new GuiTheoraCtrl()\n"
- "{\n"
- " theoraFile = \"videos/intro.ogv\";\n"
- " playOnWake = false;\n"
- " stopOnSleep = true;\n"
- "}\n"
- "\n"
- "Canvas.setContent( %video );\n"
- "%video.play();\n"
- "@endtsexample\n\n"
-
- "@see http://www.theora.org\n\n"
- "@ingroup GuiImages"
- );
- ImplementEnumType( GuiTheoraTranscoder,
- "Routine to use for converting Theora's Y'CbCr pixel format to RGB color space.\n\n"
- "@ingroup GuiImages" )
- { OggTheoraDecoder::TRANSCODER_Auto, "Auto", "Automatically detect most appropriate setting." },
- { OggTheoraDecoder::TRANSCODER_Generic, "Generic", "Slower but beneric transcoder that can convert all Y'CbCr input formats to RGB or RGBA output." },
- { OggTheoraDecoder::TRANSCODER_SSE2420RGBA, "SSE2420RGBA", "Fast SSE2-based transcoder with fixed conversion from 4:2:0 Y'CbCr to RGBA." },
- EndImplementEnumType;
- //-----------------------------------------------------------------------------
- GuiTheoraCtrl::GuiTheoraCtrl()
- {
- mFilename = StringTable->EmptyString();
- mDone = false;
- mStopOnSleep = false;
- mMatchVideoSize = true;
- mPlayOnWake = true;
- mRenderDebugInfo = false;
- mTranscoder = OggTheoraDecoder::TRANSCODER_Auto;
- mLoop = false;
-
- mBackgroundColor.set( 0, 0, 0, 255);
- }
- //-----------------------------------------------------------------------------
- void GuiTheoraCtrl::initPersistFields()
- {
- addGroup( "Playback");
- addField( "theoraFile", TypeStringFilename, Offset( mFilename, GuiTheoraCtrl ),
- "Theora video file to play." );
- addField( "backgroundColor", TypeColorI, Offset( mBackgroundColor, GuiTheoraCtrl ),
- "Fill color when video is not playing." );
- addField( "playOnWake", TypeBool, Offset( mPlayOnWake, GuiTheoraCtrl ),
- "Whether to start playing video when control is woken up." );
- addField( "loop", TypeBool, Offset( mLoop, GuiTheoraCtrl ),
- "Loop playback." );
- addField( "stopOnSleep", TypeBool, Offset( mStopOnSleep, GuiTheoraCtrl ),
- "Whether to stop video when control is set to sleep.\n\n"
- "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 "
- "for seeking in the video stream in the player backend and letting the time source used to synchronize video (either audio "
- "or a raw timer) get far ahead of frame decoding will cause possibly very long delays when the control is woken up again." );
- addField( "matchVideoSize", TypeBool, Offset( mMatchVideoSize, GuiTheoraCtrl ),
- "Whether to automatically match control extents to the video size." );
- addField( "renderDebugInfo", TypeBool, Offset( mRenderDebugInfo, GuiTheoraCtrl ),
- "If true, displays an overlay on top of the video with useful debugging information." );
- addField( "transcoder", TYPEID< OggTheoraDecoder::ETranscoder >(), Offset( mTranscoder, GuiTheoraCtrl ),
- "The routine to use for Y'CbCr to RGB conversion." );
- endGroup( "Playback" );
- Parent::initPersistFields();
- }
- //-----------------------------------------------------------------------------
- void GuiTheoraCtrl::setFile( const String& filename )
- {
- mDone = false;
- mFilename = filename;
- mTheoraTexture.setFile( filename );
-
- if( mMatchVideoSize && mTheoraTexture.isReady() )
- setExtent( Point2I( mTheoraTexture.getWidth(), mTheoraTexture.getHeight() ) );
- OggTheoraDecoder* decoder = mTheoraTexture._getTheora();
- if( decoder != NULL )
- decoder->setTranscoder( mTranscoder );
- }
- //-----------------------------------------------------------------------------
- void GuiTheoraCtrl::play()
- {
- if( mFilename == StringTable->EmptyString() )
- return;
-
- if( !mTheoraTexture.isPlaying() )
- {
- mDone = false;
- mTheoraTexture.play();
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTheoraCtrl::pause()
- {
- if( !mTheoraTexture.isPlaying() )
- {
- Con::errorf( "GuiTheoraCtrl::pause - not playing" );
- return;
- }
-
- mTheoraTexture.pause();
- }
- //-----------------------------------------------------------------------------
- void GuiTheoraCtrl::stop()
- {
- mTheoraTexture.stop();
- mDone = true;
- }
- //-----------------------------------------------------------------------------
- bool GuiTheoraCtrl::onWake()
- {
- if( !Parent::onWake() )
- return false;
- if( !mTheoraTexture.isReady() )
- setFile( mFilename );
-
- if( mPlayOnWake && !mTheoraTexture.isPlaying() )
- play();
- return true;
- }
- //-----------------------------------------------------------------------------
- void GuiTheoraCtrl::onSleep()
- {
- Parent::onSleep();
- if( mTheoraTexture.isPlaying() )
- {
- if( mStopOnSleep )
- stop();
- else
- pause();
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTheoraCtrl::onRender(Point2I offset, const RectI &updateRect)
- {
- const RectI rect(offset, getBounds().extent);
- if( mTheoraTexture.isReady() )
- {
- mTheoraTexture.refresh();
- if( mTheoraTexture.isPlaying()
- || mTheoraTexture.isPaused() )
- {
- // Draw the frame.
-
- GFXDrawUtil* drawUtil = GFX->getDrawUtil();
- drawUtil->clearBitmapModulation();
- drawUtil->drawBitmapStretch( mTheoraTexture.getTexture(), rect );
-
- // Draw frame info, if requested.
-
- if( mRenderDebugInfo )
- {
- String info = String::ToString( "Frame Number: %i | Frame Time: %.2fs | Playback Time: %.2fs | Dropped: %i",
- mTheoraTexture.getFrameNumber(),
- mTheoraTexture.getFrameTime(),
- F32( mTheoraTexture.getPosition() ) / 1000.f,
- mTheoraTexture.getNumDroppedFrames() );
-
- drawUtil->setBitmapModulation( mProfile->mFontColors[ 0 ] );
- drawUtil->drawText( mProfile->mFont, localToGlobalCoord( Point2I( 0, 0 ) ), info, mProfile->mFontColors );
- }
- }
- else
- {
- if(mLoop)
- {
- play();
- } else {
- mDone = true;
- }
- }
- }
- else
- GFX->getDrawUtil()->drawRectFill(rect, mBackgroundColor); // black rect
- renderChildControls(offset, updateRect);
- }
- //-----------------------------------------------------------------------------
- void GuiTheoraCtrl::inspectPostApply()
- {
- if( !mTheoraTexture.getFilename().equal( mFilename, String::NoCase ) )
- {
- stop();
- setFile( mFilename );
-
- if( mPlayOnWake && !mTheoraTexture.isPlaying() )
- play();
- }
-
- if( mMatchVideoSize && mTheoraTexture.isReady() )
- setExtent( Point2I( mTheoraTexture.getWidth(), mTheoraTexture.getHeight() ) );
- OggTheoraDecoder* decoder = mTheoraTexture._getTheora();
- if( decoder != NULL )
- decoder->setTranscoder( mTranscoder );
-
- Parent::inspectPostApply();
- }
- //=============================================================================
- // API.
- //=============================================================================
- // MARK: ---- API ----
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTheoraCtrl, setFile, void, ( const char* filename ),,
- "Set the video file to play. If a video is already playing, playback is stopped and "
- "the new video file is loaded.\n\n"
- "@param filename The video file to load." )
- {
- object->setFile( filename );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTheoraCtrl, play, void, (),,
- "Start playing the video. If the video is already playing, the call is ignored." )
- {
- object->play();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTheoraCtrl, pause, void, (),,
- "Pause playback of the video. If the video is not currently playing, the call is ignored.\n\n"
- "While stopped, the control displays the last frame." )
- {
- object->pause();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTheoraCtrl, stop, void, (),,
- "Stop playback of the video. The next call to play() will then start playback from the beginning of the video.\n\n"
- "While stopped, the control renders empty with just the background color." )
- {
- object->stop();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTheoraCtrl, getCurrentTime, F32, (),,
- "Get the current playback time.\n\n"
- "@return The elapsed playback time in seconds." )
- {
- return object->getCurrentTime();
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTheoraCtrl, isPlaybackDone, bool, (),,
- "Test whether the video has finished playing.\n\n"
- "@return True if the video has finished playing, false otherwise." )
- {
- return object->isPlaybackDone();
- }
- #endif // TORQUE_OGGTHEORA
|