summaryrefslogtreecommitdiff
path: root/video/videoservices.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /video/videoservices.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'video/videoservices.cpp')
-rw-r--r--video/videoservices.cpp1464
1 files changed, 1464 insertions, 0 deletions
diff --git a/video/videoservices.cpp b/video/videoservices.cpp
new file mode 100644
index 0000000..24417c7
--- /dev/null
+++ b/video/videoservices.cpp
@@ -0,0 +1,1464 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "filesystem.h"
+#include "tier1/strtools.h"
+#include "tier1/utllinkedlist.h"
+#include "tier1/KeyValues.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/MaterialSystemUtil.h"
+#include "materialsystem/itexture.h"
+#include "vgui/ILocalize.h"
+#include "vtf/vtf.h"
+#include "pixelwriter.h"
+#include "tier3/tier3.h"
+#include "platform.h"
+
+#include "videoservices.h"
+#include "video_macros.h"
+
+#include "tier0/memdbgon.h"
+
+#if defined( WIN32 )
+ #include <windows.h>
+#elif defined( OSX )
+ #include <Carbon/Carbon.h>
+#endif
+
+#if defined( USE_SDL )
+ #include "SDL.h"
+ #include "appframework/ilaunchermgr.h"
+#endif
+
+//-----------------------------------------------------------------------------
+// Platform specific video system controls & definitions
+//-----------------------------------------------------------------------------
+
+enum EPlatform_t
+{
+ PLATFORM_NONE = 0,
+ PLATFORM_WIN32 = 0x01,
+ PLATFORM_OSX = 0x02,
+ PLATFORM_XBOX_360 = 0x04,
+ PLATFORM_PS3 = 0x08,
+ PLATFORM_LINUX = 0x10
+};
+
+DEFINE_ENUM_BITWISE_OPERATORS( EPlatform_t );
+
+#if defined( IS_WINDOWS_PC )
+ const EPlatform_t thisPlatform = PLATFORM_WIN32;
+#elif defined( OSX )
+ const EPlatform_t thisPlatform = PLATFORM_OSX;
+#elif defined( _X360 )
+ const EPlatform_t thisPlatform = PLATFORM_XBOX_360;
+#elif defined( _PS3 )
+ const EPlatform_t thisPlatform = PLATFORM_PS3;
+#elif defined ( _LINUX )
+ const EPlatform_t thisPlatform = PLATFORM_LINUX;
+#else
+ #error "UNABLE TO DETERMINE PLATFORM"
+#endif
+
+
+#if defined( OSX ) || defined( LINUX )
+ILauncherMgr *g_pLauncherMgr = NULL;
+#endif
+
+
+struct VideoSystemInfo_t
+{
+ VideoSystem_t m_SystemID;
+ EPlatform_t m_Platforms;
+ const char *m_pModuleName;
+ const char *m_pInterfaceName;
+};
+
+static VideoSystemInfo_t s_VideoAppSystems[] =
+{
+ { VideoSystem::QUICKTIME, PLATFORM_WIN32 | PLATFORM_OSX, "video_quicktime", VIDEO_SUBSYSTEM_INTERFACE_VERSION },
+ { VideoSystem::BINK, PLATFORM_WIN32 | PLATFORM_OSX | PLATFORM_XBOX_360 | PLATFORM_LINUX, "video_bink", VIDEO_SUBSYSTEM_INTERFACE_VERSION },
+ //{ VideoSystem::AVI, PLATFORM_WIN32, "avi", VIDEO_SUBSYSTEM_INTERFACE_VERSION },
+ //{ VideoSystem::WMV, PLATFORM_WIN32, "wmv", VIDEO_SUBSYSTEM_INTERFACE_VERSION },
+ { VideoSystem::WEBM, PLATFORM_LINUX, "video_webm", VIDEO_SUBSYSTEM_INTERFACE_VERSION },
+
+ { VideoSystem::NONE, PLATFORM_NONE, nullptr, nullptr } // Required to terminate the list
+};
+
+
+
+//-----------------------------------------------------------------------------
+// Setup Singleton for accessing Valve Video Services
+//-----------------------------------------------------------------------------
+static CValveVideoServices g_VALVeVIDEO;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CValveVideoServices, IVideoServices, VIDEO_SERVICES_INTERFACE_VERSION, g_VALVeVIDEO );
+
+
+static CVideoCommonServices g_VALVEVIDEOCommon;
+
+
+//-----------------------------------------------------------------------------
+// Valve Video Services implementation
+//-----------------------------------------------------------------------------
+CValveVideoServices::CValveVideoServices() :
+ m_nInstalledSystems( 0 ),
+ m_bInitialized( false ),
+ m_nMaterialCount( 0 )
+{
+ for ( int i = 0; i < VideoSystem::VIDEO_SYSTEM_COUNT; i++ )
+ {
+ m_VideoSystemModule[i] = nullptr;
+ m_VideoSystems[i] = nullptr;
+ m_VideoSystemType[i] = VideoSystem::NONE;
+ m_VideoSystemFeatures[i] = VideoSystemFeature::NO_FEATURES;
+ }
+
+}
+
+
+CValveVideoServices::~CValveVideoServices()
+{
+ DisconnectVideoLibraries( );
+}
+
+
+bool CValveVideoServices::Connect( CreateInterfaceFn factory )
+{
+ if ( !BaseClass::Connect( factory ) )
+ {
+ return false;
+ }
+
+ if ( g_pFullFileSystem == nullptr || materials == nullptr )
+ {
+ Msg( "Valve Video Services unable to connect due to missing dependent system\n" );
+ return false;
+ }
+
+#if defined( USE_SDL )
+ g_pLauncherMgr = (ILauncherMgr *)factory( SDLMGR_INTERFACE_VERSION, NULL );
+#endif
+
+ if ( !ConnectVideoLibraries( factory ) )
+ {
+ return false;
+ }
+
+ return ( true );
+}
+
+
+void CValveVideoServices::Disconnect()
+{
+ DisconnectVideoLibraries();
+}
+
+
+void* CValveVideoServices::QueryInterface( const char *pInterfaceName )
+{
+ if ( Q_strncmp( pInterfaceName, VIDEO_SERVICES_INTERFACE_VERSION, Q_strlen( VIDEO_SERVICES_INTERFACE_VERSION ) + 1) == 0 )
+ {
+ return (IVideoServices*) this;
+ }
+
+ return nullptr;
+}
+
+
+bool CValveVideoServices::ConnectVideoLibraries( CreateInterfaceFn factory )
+{
+ // Don't connect twice..
+ AssertExitF( m_bInitialized == false );
+
+ int n = 0;
+
+ while ( IS_NOT_EMPTY( s_VideoAppSystems[n].m_pModuleName ) && s_VideoAppSystems[n].m_SystemID != VideoSystem::NONE )
+ {
+ if (BITFLAGS_SET( s_VideoAppSystems[n].m_Platforms, thisPlatform ) )
+ {
+ bool success = false;
+ CSysModule *pModule = Sys_LoadModule(s_VideoAppSystems[n].m_pModuleName );
+ if( pModule != nullptr )
+ {
+ CreateInterfaceFn fn = Sys_GetFactory( pModule );
+ if ( fn != nullptr )
+ {
+
+ IVideoSubSystem *pVideoSystem = (IVideoSubSystem*) fn( s_VideoAppSystems[n].m_pInterfaceName, NULL );
+ if ( pVideoSystem != nullptr && pVideoSystem->Connect( factory ) )
+ {
+ if ( pVideoSystem->InitializeVideoSystem( &g_VALVEVIDEOCommon ) )
+ {
+ int slotNum = (int) pVideoSystem->GetSystemID();
+
+ if ( IS_IN_RANGECOUNT( slotNum, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ) )
+ {
+ Assert( m_VideoSystemModule[slotNum] == nullptr );
+ m_VideoSystemModule[slotNum] = pModule;
+ m_VideoSystems[slotNum] = pVideoSystem;
+
+ m_nInstalledSystems++;
+ success = true;
+ }
+ }
+ }
+ }
+
+ if ( success == false )
+ {
+
+ Msg( "Error occurred while attempting to load and initialize Video Subsystem\n Video Subsystem module '%s'\n Video Subsystem Interface '%s'", s_VideoAppSystems[n].m_pModuleName, s_VideoAppSystems[n].m_pInterfaceName );
+ Sys_UnloadModule( pModule );
+ }
+ }
+ }
+
+ n++;
+ }
+
+ // now we query each video system for its capabilities, and supported file extensions
+ for ( int i = VideoSystem::VIDEO_SYSTEM_FIRST; i < VideoSystem::VIDEO_SYSTEM_COUNT; i++ )
+ {
+ IVideoSubSystem *pSubSystem = m_VideoSystems[i];
+ if ( pSubSystem != nullptr )
+ {
+ m_VideoSystemType[i] = pSubSystem->GetSystemID();
+ m_VideoSystemFeatures[i] = pSubSystem->GetSupportedFeatures();
+
+ // get every file extension it handles, and the info about it
+ int eCount = pSubSystem->GetSupportedFileExtensionCount();
+ Assert( eCount > 0 );
+
+ for ( int n = 0; n < eCount; n++ )
+ {
+ VideoFileExtensionInfo_t extInfoRec;
+
+ extInfoRec.m_FileExtension = pSubSystem->GetSupportedFileExtension( n );
+ extInfoRec.m_VideoSubSystem = pSubSystem->GetSystemID();
+ extInfoRec.m_VideoFeatures = pSubSystem->GetSupportedFileExtensionFeatures( n );
+
+ AssertPtr( extInfoRec.m_FileExtension );
+
+ m_ExtInfo.AddToTail( extInfoRec );
+ }
+ }
+ }
+
+ m_bInitialized = true;
+
+ return true;
+}
+
+
+bool CValveVideoServices::DisconnectVideoLibraries()
+{
+ if ( !m_bInitialized )
+ {
+ return false;
+ }
+
+ // free up any objects/resources still out there
+ DestroyAllVideoInterfaces();
+
+ for ( int i = 0; i < VideoSystem::VIDEO_SYSTEM_COUNT; i++ )
+ {
+ if ( m_VideoSystems[i] != nullptr )
+ {
+ m_VideoSystems[i]->ShutdownVideoSystem();
+ m_VideoSystems[i]->Disconnect();
+ m_VideoSystems[i] = nullptr;
+ }
+
+ if ( m_VideoSystemModule[i] != nullptr )
+ {
+ Sys_UnloadModule( m_VideoSystemModule[i] );
+ m_VideoSystemModule[i] = nullptr;
+ }
+
+ m_VideoSystemType[i] = VideoSystem::NONE;
+ m_VideoSystemFeatures[i] = VideoSystemFeature::NO_FEATURES;
+ }
+
+ m_bInitialized = false;
+
+ return true;
+}
+
+
+int CValveVideoServices::DestroyAllVideoInterfaces()
+{
+ int n = m_RecorderList.Count() + m_MaterialList.Count();
+
+ for ( int i = m_RecorderList.Count() -1; i >= 0; i-- )
+ {
+ DestroyVideoRecorder( (IVideoRecorder*) m_RecorderList[i].m_pObject );
+ }
+
+ for ( int i = m_MaterialList.Count() -1; i >= 0; i-- )
+ {
+ DestroyVideoMaterial( (IVideoMaterial*) m_MaterialList[i].m_pObject );
+ }
+
+ return n;
+}
+
+
+InitReturnVal_t CValveVideoServices::Init()
+{
+ InitReturnVal_t nRetVal = BaseClass::Init();
+ if ( nRetVal != INIT_OK )
+ {
+ return nRetVal;
+ }
+
+ // Initialize all loaded subsystems
+ for ( int n = VideoSystem::VIDEO_SYSTEM_FIRST; n < VideoSystem::VIDEO_SYSTEM_COUNT; n++ )
+ {
+ if ( m_VideoSystems[n] != nullptr )
+ {
+ nRetVal = m_VideoSystems[n]->Init();
+ if ( nRetVal != INIT_OK )
+ {
+ return nRetVal;
+ }
+ }
+ }
+
+ return INIT_OK;
+}
+
+
+void CValveVideoServices::Shutdown()
+{
+ DestroyAllVideoInterfaces();
+
+ // Shutdown all loaded subsystems
+ for ( int n = VideoSystem::VIDEO_SYSTEM_FIRST; n < VideoSystem::VIDEO_SYSTEM_COUNT; n++ )
+ {
+ if ( m_VideoSystems[n] != nullptr )
+ {
+ m_VideoSystems[n]->Shutdown();
+ }
+ }
+
+ BaseClass::Shutdown();
+}
+
+
+// ===========================================================================
+// Inherited from IVideoServices
+// ===========================================================================
+
+// Query the available video systems
+int CValveVideoServices::GetAvailableVideoSystemCount()
+{
+ return m_nInstalledSystems;
+}
+
+
+// returns the enumerated video system, *IF* it is installed and working
+VideoSystem_t CValveVideoServices::GetAvailableVideoSystem( int n )
+{
+ if ( n< 0 || n >= m_nInstalledSystems )
+ {
+ return VideoSystem::NONE;
+ }
+
+ for ( int i = VideoSystem::VIDEO_SYSTEM_FIRST, c = 0; i < VideoSystem::VIDEO_SYSTEM_COUNT; i++ )
+ {
+ if ( m_VideoSystems[i] != nullptr )
+ {
+ if ( c == n )
+ {
+ return m_VideoSystemType[i];
+ }
+ c++;
+ }
+ }
+
+ return VideoSystem::NONE;
+}
+
+
+// ===========================================================================
+// returns the index for the video system...
+// ... provided that system is installed and available to do something
+// ===========================================================================
+int CValveVideoServices::GetIndexForSystem( VideoSystem_t n )
+{
+ if ( n >= VideoSystem::VIDEO_SYSTEM_FIRST && n < VideoSystem::VIDEO_SYSTEM_COUNT && m_nInstalledSystems > 0 )
+ {
+ int i = (int) n;
+ if ( m_VideoSystems[i] != nullptr && m_VideoSystemFeatures[i] != VideoSystemFeature::NO_FEATURES )
+ {
+ return i;
+ }
+ }
+
+ return SYSTEM_NOT_FOUND;
+}
+
+
+VideoSystem_t CValveVideoServices::GetSystemForIndex( int n )
+{
+ if ( n >= VideoSystem::VIDEO_SYSTEM_FIRST && n < VideoSystem::VIDEO_SYSTEM_COUNT && m_nInstalledSystems > 0 )
+ {
+ if ( m_VideoSystems[n] != nullptr && m_VideoSystemFeatures[n] != VideoSystemFeature::NO_FEATURES )
+ {
+ return (VideoSystem_t) n;
+ }
+ }
+
+ return VideoSystem::NONE;
+}
+
+
+// ===========================================================================
+// video system query functions
+// ===========================================================================
+bool CValveVideoServices::IsVideoSystemAvailable( VideoSystem_t videoSystem )
+{
+ int n = GetIndexForSystem( videoSystem );
+ return ( n != SYSTEM_NOT_FOUND ) ? true : false;
+}
+
+
+VideoSystemStatus_t CValveVideoServices::GetVideoSystemStatus( VideoSystem_t videoSystem )
+{
+ int n = GetIndexForSystem( videoSystem );
+ return ( n!= SYSTEM_NOT_FOUND ) ? m_VideoSystems[n]->GetSystemStatus() : VideoSystemStatus::NOT_INSTALLED;
+}
+
+
+VideoSystemFeature_t CValveVideoServices::GetVideoSystemFeatures( VideoSystem_t videoSystem )
+{
+ int n = GetIndexForSystem( videoSystem );
+ return ( n!= SYSTEM_NOT_FOUND ) ? m_VideoSystemFeatures[n] : VideoSystemFeature::NO_FEATURES;
+
+}
+
+
+const char *CValveVideoServices::GetVideoSystemName( VideoSystem_t videoSystem )
+{
+ int n = GetIndexForSystem( videoSystem );
+ return ( n!= SYSTEM_NOT_FOUND ) ? m_VideoSystems[n]->GetVideoSystemName() : nullptr;
+}
+
+
+VideoSystem_t CValveVideoServices::FindNextSystemWithFeature( VideoSystemFeature_t features, VideoSystem_t startAfter )
+{
+ if ( ( features & VideoSystemFeature::ALL_VALID_FEATURES ) == 0 )
+ {
+ return VideoSystem::NONE;
+ }
+
+ int start = VideoSystem::VIDEO_SYSTEM_FIRST;
+ if ( startAfter != VideoSystem::NONE && IS_IN_RANGECOUNT( startAfter, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ) )
+ {
+ start = (int) startAfter;
+ }
+
+ for ( int i = start; i < VideoSystem::VIDEO_SYSTEM_COUNT; i++ )
+ {
+ if ( m_VideoSystems[i] != nullptr && BITFLAGS_SET( m_VideoSystemFeatures[i], features ) )
+ {
+ return (VideoSystem_t) i;
+ }
+ }
+
+ return VideoSystem::NONE;
+}
+
+
+// ===========================================================================
+// video services status functions
+// ===========================================================================
+VideoResult_t CValveVideoServices::GetLastResult()
+{
+ return m_LastResult;
+}
+
+
+VideoResult_t CValveVideoServices::SetResult( VideoResult_t resultCode )
+{
+ m_LastResult = resultCode;
+ return resultCode;
+}
+
+
+// ===========================================================================
+// deal with video file extensions and video system mappings
+// ===========================================================================
+int CValveVideoServices::GetSupportedFileExtensionCount( VideoSystem_t videoSystem )
+{
+ int n = GetIndexForSystem( videoSystem );
+
+ return ( n == SYSTEM_NOT_FOUND ) ? 0 : m_VideoSystems[n]->GetSupportedFileExtensionCount();
+}
+
+
+const char *CValveVideoServices::GetSupportedFileExtension( VideoSystem_t videoSystem, int extNum )
+{
+ int n = GetIndexForSystem( videoSystem );
+
+ int c = ( n == SYSTEM_NOT_FOUND ) ? 0 : m_VideoSystems[n]->GetSupportedFileExtensionCount();;
+
+ return ( extNum < 0 || extNum >= c ) ? nullptr : m_VideoSystems[n]->GetSupportedFileExtension( extNum );
+
+}
+
+
+VideoSystemFeature_t CValveVideoServices::GetSupportedFileExtensionFeatures( VideoSystem_t videoSystem, int extNum )
+{
+ int n = GetIndexForSystem( videoSystem );
+
+ int c = ( n == SYSTEM_NOT_FOUND ) ? 0 : m_VideoSystems[n]->GetSupportedFileExtensionCount();
+
+ return ( extNum < 0 || extNum >= c ) ? VideoSystemFeature::NO_FEATURES : m_VideoSystems[n]->GetSupportedFileExtensionFeatures( extNum );
+}
+
+
+VideoSystem_t CValveVideoServices::LocateVideoSystemForPlayingFile( const char *pFileName, VideoSystemFeature_t playMode )
+{
+ SetResult( VideoResult::BAD_INPUT_PARAMETERS );
+ AssertExitV( IS_NOT_EMPTY( pFileName ), VideoSystem::NONE );
+
+ VideoSystem_t theSystem = LocateSystemAndFeaturesForFileName( pFileName, nullptr, playMode );
+
+ SetResult( VideoResult::SUCCESS );
+ return theSystem;
+}
+
+
+// ===========================================================================
+// Given a video file name, possibly with a set extension, locate the file
+// or a suitable substitute that is playable on the current system
+// ===========================================================================
+VideoResult_t CValveVideoServices::LocatePlayableVideoFile( const char *pSearchFileName, const char *pPathID, VideoSystem_t *pPlaybackSystem, char *pPlaybackFileName, int fileNameMaxLen, VideoSystemFeature_t playMode )
+{
+ AssertExitV( IS_NOT_EMPTY( pSearchFileName ) || pPlaybackSystem == nullptr || pPlaybackSystem == nullptr || fileNameMaxLen <= 0, SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
+
+ VideoResult_t Status = ResolveToPlayableVideoFile( pSearchFileName, pPathID, VideoSystem::DETERMINE_FROM_FILE_EXTENSION, playMode,
+ true, pPlaybackFileName, fileNameMaxLen, pPlaybackSystem );
+
+ return SetResult( Status );
+}
+
+
+
+// ===========================================================================
+// Create/destroy a video material
+// ===========================================================================
+IVideoMaterial* CValveVideoServices::CreateVideoMaterial( const char *pMaterialName, const char *pVideoFileName, const char *pPathID, VideoPlaybackFlags_t playbackFlags, VideoSystem_t videoSystem, bool PlayAlternateIfNotAvailable )
+{
+ SetResult( VideoResult::BAD_INPUT_PARAMETERS );
+ AssertExitV( IS_NOT_EMPTY( pVideoFileName ), nullptr );
+ AssertExitV( videoSystem == VideoSystem::DETERMINE_FROM_FILE_EXTENSION || IS_IN_RANGECOUNT( videoSystem, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ), nullptr );
+
+ // We need to resolve the filename and video system
+
+ char ResolvedFilePath[MAX_PATH];
+ VideoSystem_t actualVideoSystem = videoSystem;
+
+ VideoResult_t Status = ResolveToPlayableVideoFile( pVideoFileName, pPathID, videoSystem, VideoSystemFeature::PLAY_VIDEO_FILE_IN_MATERIAL, PlayAlternateIfNotAvailable,
+ ResolvedFilePath, sizeof(ResolvedFilePath), &actualVideoSystem );
+
+ SetResult( Status );
+ if ( Status != VideoResult::SUCCESS )
+ {
+ return nullptr;
+ }
+
+ int sysIndex = GetIndexForSystem( actualVideoSystem );
+
+ if ( sysIndex == SYSTEM_NOT_FOUND )
+ {
+ SetResult( VideoResult::SYSTEM_ERROR_OCCURED );
+ return nullptr;
+ }
+
+ // Create the video material
+ IVideoMaterial *pMaterial = m_VideoSystems[sysIndex]->CreateVideoMaterial( pMaterialName, ResolvedFilePath, playbackFlags );
+
+ // Update our list, and return
+ if ( pMaterial != nullptr )
+ {
+ CActiveVideoObjectRecord_t info;
+ info.m_pObject = pMaterial;
+ info.m_VideoSystem = sysIndex;
+ m_MaterialList.AddToTail( info );
+ }
+
+ SetResult( m_VideoSystems[sysIndex]->GetLastResult() );
+ return pMaterial;
+}
+
+
+VideoResult_t CValveVideoServices::DestroyVideoMaterial( IVideoMaterial* pVideoMaterial )
+{
+ AssertPtrExitV( pVideoMaterial, SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
+
+ for ( int i = 0; i < m_MaterialList.Count(); i++ )
+ {
+ if ( m_MaterialList[i].m_pObject == pVideoMaterial )
+ {
+ VideoResult_t Status = m_VideoSystems[ m_MaterialList[i].m_VideoSystem ]->DestroyVideoMaterial( pVideoMaterial );
+ m_MaterialList.Remove( i );
+
+ return SetResult( Status );
+ }
+ }
+
+ return SetResult( VideoResult::RECORDER_NOT_FOUND );
+
+
+ return VideoResult::SUCCESS;
+}
+
+
+int CValveVideoServices::GetUniqueMaterialID()
+{
+ m_nMaterialCount++;
+ return m_nMaterialCount;
+}
+
+// ===========================================================================
+// Query availabilily of codec for encoding video
+// ===========================================================================
+VideoResult_t CValveVideoServices::IsRecordCodecAvailable( VideoSystem_t videoSystem, VideoEncodeCodec_t codec )
+{
+ AssertExitV( codec >= VideoEncodeCodec::DEFAULT_CODEC && codec < VideoEncodeCodec::CODEC_COUNT, SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
+
+ int n = GetIndexForSystem( videoSystem );
+
+ if ( n == SYSTEM_NOT_FOUND )
+ {
+ return SetResult( VideoResult::SYSTEM_NOT_AVAILABLE );
+ }
+
+ return m_VideoSystems[n]->CheckCodecAvailability( codec );
+}
+
+
+// ===========================================================================
+// Create/destroy a video encoder
+// ===========================================================================
+IVideoRecorder* CValveVideoServices::CreateVideoRecorder( VideoSystem_t videoSystem )
+{
+ int n = GetIndexForSystem( videoSystem );
+
+ if ( n == SYSTEM_NOT_FOUND )
+ {
+ SetResult( VideoResult::SYSTEM_NOT_AVAILABLE );
+ return nullptr;
+ }
+
+ if ( !BITFLAGS_SET( m_VideoSystemFeatures[n], VideoSystemFeature::ENCODE_VIDEO_TO_FILE ) )
+ {
+ SetResult( VideoResult::FEATURE_NOT_AVAILABLE );
+ return nullptr;
+ }
+
+ IVideoRecorder *pRecorder = m_VideoSystems[n]->CreateVideoRecorder();
+
+ if ( pRecorder != nullptr )
+ {
+ CActiveVideoObjectRecord_t info;
+ info.m_pObject = pRecorder;
+ info.m_VideoSystem = n;
+ m_RecorderList.AddToTail( info );
+ }
+
+ SetResult( m_VideoSystems[n]->GetLastResult() );
+ return pRecorder;
+}
+
+
+VideoResult_t CValveVideoServices::DestroyVideoRecorder( IVideoRecorder *pVideoRecorder )
+{
+ AssertPtrExitV( pVideoRecorder, SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
+
+ for ( int i = 0; i < m_RecorderList.Count(); i++ )
+ {
+ if ( m_RecorderList[i].m_pObject == pVideoRecorder )
+ {
+ VideoResult_t Status = m_VideoSystems[ m_RecorderList[i].m_VideoSystem ]->DestroyVideoRecorder( pVideoRecorder );
+ m_RecorderList.Remove( i );
+
+ return SetResult( Status );
+ }
+ }
+
+ return SetResult( VideoResult::RECORDER_NOT_FOUND );
+
+}
+
+
+// ===========================================================================
+// Plays a given video file until it completes or the user aborts
+// ===========================================================================
+VideoResult_t CValveVideoServices::PlayVideoFileFullScreen( const char *pFileName, const char *pPathID, void *mainWindow, int windowWidth, int windowHeight, int desktopWidth, int desktopHeight, bool windowed, float forcedMinTime, VideoPlaybackFlags_t playbackFlags, VideoSystem_t videoSystem, bool PlayAlternateIfNotAvailable )
+{
+ SetResult( VideoResult::BAD_INPUT_PARAMETERS );
+ AssertExitV( IS_NOT_EMPTY( pFileName ), VideoResult::BAD_INPUT_PARAMETERS );
+ AssertExitV( videoSystem == VideoSystem::DETERMINE_FROM_FILE_EXTENSION || IS_IN_RANGECOUNT( videoSystem, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ), VideoResult::BAD_INPUT_PARAMETERS );
+
+ char ResolvedFilePath[MAX_PATH];
+ VideoSystem_t actualVideoSystem = videoSystem;
+
+ VideoResult_t Status = ResolveToPlayableVideoFile( pFileName, pPathID, videoSystem, VideoSystemFeature::PLAY_VIDEO_FILE_FULL_SCREEN, PlayAlternateIfNotAvailable,
+ ResolvedFilePath, sizeof(ResolvedFilePath), &actualVideoSystem );
+
+ if ( Status != VideoResult::SUCCESS )
+ {
+ return Status;
+ }
+
+ int sysIndex = GetIndexForSystem( actualVideoSystem );
+
+ if ( sysIndex != SYSTEM_NOT_FOUND )
+ {
+ return SetResult( m_VideoSystems[sysIndex]->PlayVideoFileFullScreen( ResolvedFilePath, mainWindow, windowWidth, windowHeight, desktopWidth, desktopHeight, windowed, forcedMinTime, playbackFlags ) );
+ }
+ else
+ {
+ return SetResult( VideoResult::SYSTEM_ERROR_OCCURED );
+ }
+
+}
+
+
+// ===========================================================================
+// Functions to connect sound systems to video systems
+// ===========================================================================
+VideoResult_t CValveVideoServices::SoundDeviceCommand( VideoSoundDeviceOperation_t operation, void *pDevice, void *pData, VideoSystem_t videoSystem )
+{
+ AssertExitV( IS_IN_RANGECOUNT( operation, 0, VideoSoundDeviceOperation::OPERATION_COUNT ), SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
+
+ AssertExitV( videoSystem == VideoSystem::ALL_VIDEO_SYSTEMS || IS_IN_RANGECOUNT( videoSystem, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ), SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
+
+ int startIdx = (int) VideoSystem::VIDEO_SYSTEM_FIRST;
+ int lastIdx = (int) VideoSystem::VIDEO_SYSTEM_COUNT - 1;
+
+ if ( videoSystem != VideoSystem::ALL_VIDEO_SYSTEMS )
+ {
+ startIdx = lastIdx = GetIndexForSystem( videoSystem );
+ if ( startIdx == SYSTEM_NOT_FOUND )
+ {
+ return SetResult( VideoResult::SYSTEM_NOT_AVAILABLE );
+ }
+ }
+
+ VideoResult_t result = VideoResult::SYSTEM_NOT_AVAILABLE;
+
+ for ( int i = startIdx; i <= lastIdx; i++ )
+ {
+ int n = GetIndexForSystem( (VideoSystem_t) i );
+ if ( n != SYSTEM_NOT_FOUND )
+ {
+ result = m_VideoSystems[n]->VideoSoundDeviceCMD( operation, pDevice, pData );
+ }
+ }
+
+ return SetResult( result );
+}
+
+
+// ===========================================================================
+// Sets the sound devices that the video will decode to
+// ===========================================================================
+const wchar_t *CValveVideoServices::GetCodecName( VideoEncodeCodec_t nCodec )
+{
+ static const char *s_pCodecLookup[VideoEncodeCodec::CODEC_COUNT] =
+ {
+ "#Codec_MPEG2",
+ "#Codec_MPEG4",
+ "#Codec_H261",
+ "#Codec_H263",
+ "#Codec_H264",
+ "#Codec_MJPEG_A",
+ "#Codec_MJPEG_B",
+ "#Codec_SORENSON3",
+ "#Codec_CINEPACK",
+ "#Codec_WEBM",
+ };
+
+ if ( nCodec < 0 || nCodec >= VideoEncodeCodec::CODEC_COUNT )
+ {
+ AssertMsg( 0, "Invalid codec in CValveVideoServices::GetCodecName()" );
+ return NULL;
+ }
+
+ return g_pVGuiLocalize->Find( s_pCodecLookup[ nCodec ] );
+}
+
+// ===========================================================================
+// Functions to determine which file and video system to use
+// ===========================================================================
+VideoResult_t CValveVideoServices::ResolveToPlayableVideoFile( const char *pFileName, const char *pPathID, VideoSystem_t videoSystem, VideoSystemFeature_t requiredFeature,
+ bool PlayAlternateIfNotAvailable, char *pResolvedFileName, int resolvedFileNameMaxLen, VideoSystem_t *pResolvedVideoSystem )
+{
+ SetResult( VideoResult::BAD_INPUT_PARAMETERS );
+ AssertExitV( IS_NOT_EMPTY( pFileName ), VideoResult::BAD_INPUT_PARAMETERS );
+ AssertExitV( videoSystem == VideoSystem::DETERMINE_FROM_FILE_EXTENSION || IS_IN_RANGECOUNT( videoSystem, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ), VideoResult::BAD_INPUT_PARAMETERS );
+ AssertExitV( requiredFeature != VideoSystemFeature::NO_FEATURES, VideoResult::BAD_INPUT_PARAMETERS );
+ AssertExitV( pResolvedFileName != nullptr && resolvedFileNameMaxLen > 0 && pResolvedVideoSystem != nullptr, VideoResult::BAD_INPUT_PARAMETERS );
+
+ // clear results should we return failure
+ pResolvedFileName[0] = nullchar;
+ *pResolvedVideoSystem = VideoSystem::NONE;
+
+ int sysIdx = SYSTEM_NOT_FOUND;
+ VideoSystemFeature_t sysFeatures = VideoSystemFeature::NO_FEATURES;
+
+ // check the file extension to see if it specifies searching for any compatible video files
+ // if so, override a couple input values
+ if ( !IsMatchAnyExtension( pFileName ) )
+ {
+ goto search_for_video;
+ }
+
+ // is the requested video system available?
+
+ // We start with either the specified video system.. OR.. we choose the system based on the file extension
+ // Get the system and if it's valid, it's available features
+ if ( videoSystem != VideoSystem::DETERMINE_FROM_FILE_EXTENSION )
+ {
+ sysIdx = GetIndexForSystem( videoSystem ); // Caller specified the video system
+ sysFeatures = ( sysIdx != SYSTEM_NOT_FOUND ) ? m_VideoSystemFeatures[sysIdx] : VideoSystemFeature::NO_FEATURES;
+ }
+ else
+ {
+ // We need to determine the system to use based on filename
+ sysIdx = GetIndexForSystem( LocateSystemAndFeaturesForFileName( pFileName, &sysFeatures, requiredFeature ) );
+ }
+
+ // if we don't have a system to play this video.. and aren't allowed to look for an alternative...
+ if ( sysIdx == SYSTEM_NOT_FOUND && PlayAlternateIfNotAvailable == false )
+ {
+ return SetResult( VideoResult::VIDEO_SYSTEM_NOT_FOUND ); // return failure
+ }
+
+ char ActualFilePath[MAX_PATH];
+
+ // Examine the requested of inferred video system to see if it can do what we want,
+ // and if so, see if the corresponding file is actually found (we support search paths)
+
+ // Decision Path for when we have a preferred/specified video system specified to use
+ if ( sysIdx != SYSTEM_NOT_FOUND )
+ {
+ bool fileFound = false;
+
+ // if the request system can do the task, see if we can find the file as supplied by the caller
+ if ( BITFLAGS_SET( sysFeatures, requiredFeature ) )
+ {
+ if ( V_IsAbsolutePath( pFileName ) )
+ {
+ V_strncpy( ActualFilePath, pFileName, sizeof( ActualFilePath ) );
+ fileFound = g_pFullFileSystem->FileExists( pFileName, nullptr );
+ }
+ else
+ {
+ fileFound = ( g_pFullFileSystem->RelativePathToFullPath( pFileName, pPathID, ActualFilePath, sizeof( ActualFilePath ) ) != nullptr );
+ }
+ }
+ else // The specified video system does not support this (required) feature
+ {
+ // if we can't search for an alternative file, tell them we don't support this
+ if ( !PlayAlternateIfNotAvailable )
+ {
+ return SetResult( VideoResult::FEATURE_NOT_AVAILABLE );
+ }
+ }
+
+ // We found the specified file, and the video system has the feature support
+ if ( fileFound )
+ {
+ // copy the resolved filename and system and report success
+ V_strncpy( pResolvedFileName, ActualFilePath, resolvedFileNameMaxLen );
+ *pResolvedVideoSystem = GetSystemForIndex( sysIdx );
+ return SetResult( VideoResult::SUCCESS );
+ }
+
+ // ok, we have the feature support but didn't find the file to use...
+ if ( !PlayAlternateIfNotAvailable )
+ {
+ // if we can't search for an alternate file, so report file not found
+ return SetResult( VideoResult::VIDEO_FILE_NOT_FOUND );
+ }
+ }
+
+ // Ok, we didn't find the file and a system that could handle it
+ // but hey, we are allowed to look for an alternate video file and system
+
+search_for_video:
+
+ // start with the passed in filespec, and change the extension to wildcard
+ char SearchFileSpec[MAX_PATH];
+ V_strncpy( SearchFileSpec, pFileName, sizeof(SearchFileSpec) );
+ V_SetExtension( SearchFileSpec, ".*", sizeof(SearchFileSpec) );
+
+ FileFindHandle_t searchHandle = 0;
+
+ const char *pMatchingFile = g_pFullFileSystem->FindFirstEx( SearchFileSpec, pPathID, &searchHandle );
+
+ while ( pMatchingFile != nullptr )
+ {
+ const char *pExt = GetFileExtension( pMatchingFile );
+
+ if ( pExt != nullptr )
+ {
+ // compare file extensions
+ for ( int i = 0; i < m_ExtInfo.Count(); i++ )
+ {
+ // do we match a known extension?
+ if ( stricmp( pExt, m_ExtInfo[i].m_FileExtension ) == STRINGS_MATCH )
+ {
+ // do we support the requested feature?
+ if ( BITFLAGS_SET( m_ExtInfo[i].m_VideoFeatures, requiredFeature ) )
+ {
+ // Make sure it's a valid system
+ sysIdx = GetIndexForSystem( m_ExtInfo[i].m_VideoSubSystem );
+ if ( sysIdx != SYSTEM_NOT_FOUND )
+ {
+
+ // Start with any optional path we got...
+ V_ExtractFilePath( pFileName, ActualFilePath, sizeof( ActualFilePath ) );
+ // Append the search match file
+ V_strncat( ActualFilePath, pMatchingFile, sizeof( ActualFilePath ) );
+
+ if ( V_IsAbsolutePath( ActualFilePath ) )
+ {
+ V_strncpy( pResolvedFileName, ActualFilePath, resolvedFileNameMaxLen );
+ }
+ else
+ {
+ g_pFullFileSystem->RelativePathToFullPath( ActualFilePath, pPathID, pResolvedFileName, resolvedFileNameMaxLen );
+ }
+
+ // Return the system
+ *pResolvedVideoSystem = GetSystemForIndex( sysIdx );
+
+ g_pFullFileSystem->FindClose( searchHandle );
+
+ return SetResult( VideoResult::SUCCESS );
+ }
+ }
+ }
+ }
+ }
+
+ // not usable.. keep searching
+ pMatchingFile = g_pFullFileSystem->FindNext( searchHandle );
+ }
+
+ // we didn't find anything we could use
+ g_pFullFileSystem->FindClose( searchHandle );
+
+ return SetResult( VideoResult::VIDEO_FILE_NOT_FOUND );
+}
+
+
+VideoSystem_t CValveVideoServices::LocateSystemAndFeaturesForFileName( const char *pFileName, VideoSystemFeature_t *pFeatures, VideoSystemFeature_t requiredFeatures )
+{
+ if ( pFeatures != nullptr)
+ {
+ *pFeatures = VideoSystemFeature::NO_FEATURES;
+ }
+
+ AssertExitV( IS_NOT_EMPTY( pFileName ), VideoSystem::NONE );
+
+ if ( m_ExtInfo.Count() < 1 )
+ {
+ return VideoSystem::NONE;
+ }
+
+ // extract the file extension
+
+ char fileExt[MAX_PATH];
+
+ const char *pExt = GetFileExtension( pFileName );
+ if ( pExt == nullptr )
+ {
+ return VideoSystem::NONE;
+ }
+
+ // lowercase it so we can compare
+ V_strncpy( fileExt, pExt, sizeof(fileExt) );
+ V_strlower( fileExt );
+
+ for ( int i = 0; i < m_ExtInfo.Count(); i++ )
+ {
+ if ( V_stricmp( fileExt, m_ExtInfo[i].m_FileExtension ) == STRINGS_MATCH )
+ {
+ // must it have certain feature support?
+ if ( requiredFeatures != VideoSystemFeature::NO_FEATURES )
+ {
+ if ( !BITFLAGS_SET( m_ExtInfo[i].m_VideoFeatures, requiredFeatures ) )
+ {
+ continue;
+ }
+ }
+
+ if ( pFeatures != nullptr)
+ {
+ *pFeatures = m_ExtInfo[i].m_VideoFeatures;
+ }
+ return m_ExtInfo[i].m_VideoSubSystem;
+ }
+ }
+
+ return VideoSystem::NONE;
+}
+
+
+bool CValveVideoServices::IsMatchAnyExtension( const char *pFileName )
+{
+ if ( IS_EMPTY_STR( pFileName ) )
+ {
+ return false;
+ }
+
+ const char* pExt = GetFileExtension( pFileName );
+ if ( pExt == nullptr )
+ {
+ return false;
+ }
+
+ return ( V_stricmp( pExt, FILE_EXTENSION_ANY_MATCHING_VIDEO ) == STRINGS_MATCH );
+}
+
+
+const char *CValveVideoServices::GetFileExtension( const char *pFileName )
+{
+ if ( pFileName == nullptr )
+ {
+ return nullptr;
+ }
+
+ const char *pExt = V_GetFileExtension( pFileName );
+
+ if ( pExt == nullptr )
+ {
+ return nullptr;
+ }
+
+ if ( pExt != pFileName && *( pExt - 1 ) == '.' )
+ {
+ pExt--;
+ }
+
+ return pExt;
+}
+
+
+
+// ===========================================================================
+// CVideoCommonServices - services used by any/multiple videoSubsystems
+// Functions are put here to avoid duplication and ensure they stay
+// consistant across all installed subsystems
+// ===========================================================================
+
+
+#ifdef WIN32
+ typedef SHORT (WINAPI *GetAsyncKeyStateFn_t)( int vKey );
+
+ static HINSTANCE s_UserDLLhInst = nullptr;
+ GetAsyncKeyStateFn_t s_pfnGetAsyncKeyState = nullptr;
+#endif
+
+CVideoCommonServices::CVideoCommonServices()
+{
+ ResetInputHandlerState();
+}
+
+
+CVideoCommonServices::~CVideoCommonServices()
+{
+ if ( m_bInputHandlerInitialized )
+ {
+ TerminateFullScreenPlaybackInputHandler();
+ }
+
+}
+
+
+void CVideoCommonServices::ResetInputHandlerState()
+{
+ m_bInputHandlerInitialized = false;
+
+ m_bScanAll = false;
+ m_bScanEsc = false;
+ m_bScanReturn = false;
+ m_bScanSpace = false;
+ m_bPauseEnabled = false;
+ m_bAbortEnabled = false;
+ m_bEscLast = false;
+ m_bReturnLast = false;
+ m_bSpaceLast = false;
+ m_bForceMinPlayTime = false;
+
+ m_bWindowed = false;
+
+ m_playbackFlags = VideoPlaybackFlags::NO_PLAYBACK_OPTIONS;
+ m_forcedMinTime = 0.0f;
+
+ m_StartTime = 0;
+
+#ifdef WIN32
+ s_UserDLLhInst = nullptr;
+ s_pfnGetAsyncKeyState = nullptr;
+#endif
+
+}
+
+// ===========================================================================
+// Calculate the proper dimensions to play a video in full screen mode
+// uses the playback flags to supply rules for streaching, scaling and
+// centering the video
+// ===========================================================================
+bool CVideoCommonServices::CalculateVideoDimensions( int videoWidth, int videoHeight, int displayWidth, int displayHeight, VideoPlaybackFlags_t playbackFlags,
+ int *pOutputWidth, int *pOutputHeight, int *pXOffset, int *pYOffset )
+{
+ AssertExitF( pOutputWidth != nullptr && pOutputHeight != nullptr && pXOffset != nullptr && pYOffset != nullptr );
+ AssertExitF( videoWidth >= 16 && videoHeight >= 16 && displayWidth > 64 && displayHeight > 64 );
+
+ // extract relevant options
+ bool bFillWindow = BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::FILL_WINDOW );
+ bool bLockAspect = BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::LOCK_ASPECT_RATIO );
+ bool bIntegralScale = BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::INTEGRAL_SCALE );
+ bool bCenterVideo = BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::CENTER_VIDEO_IN_WINDOW );
+
+ int curWidth = videoWidth;
+ int curHeight = videoHeight;
+
+ // Try and just play it actual size?
+ if ( !bFillWindow )
+ {
+ // is the window the same size or larger?
+ if ( curWidth <= displayWidth && curHeight <= displayHeight )
+ {
+ goto finish;
+ }
+ else // we need to shrink the video output
+ {
+ // if we aren't locking the aspect ratio, just shrink each axis until it fits
+ if ( !bLockAspect )
+ {
+ while ( curWidth > displayWidth)
+ {
+ curWidth = ( bIntegralScale ) ? curWidth >> 1 : displayWidth;
+ }
+ while ( curHeight > displayHeight )
+ {
+ curHeight = ( bIntegralScale ) ? curHeight >> 1 : displayHeight;
+ }
+ goto finish;
+ }
+ else // we are locking the aspect ratio, and need to shrink the video
+ {
+ // integral scale only....
+ if ( bIntegralScale )
+ {
+ while ( curWidth > displayWidth || curHeight > displayHeight)
+ {
+ curWidth >>= 1;
+ curHeight >>= 1;
+ }
+ goto finish;
+ }
+ else // can scale variably..
+ {
+ float Xfactor = ( displayWidth / curWidth );
+ float Yfactor = ( displayHeight / curHeight );
+ float scale = MIN( Xfactor, Yfactor );
+
+ curWidth = (int) ( curWidth * scale + 0.35f );
+ curHeight = (int) ( curHeight * scale + 0.35f );
+ clamp( curWidth, 0, displayWidth );
+ clamp( curHeight, 0, displayHeight );
+ goto finish;
+ }
+
+ }
+ }
+ }
+
+ // ok.. we are wanting to fill the window....
+ if ( bFillWindow )
+ {
+ // are we locking the aspect ratio?
+ if ( bLockAspect )
+ {
+ // are we only allowed to scale integrally?
+ if ( bIntegralScale )
+ {
+ while ( (curWidth << 1) <= displayWidth && (curHeight << 1) <= displayHeight )
+ {
+ curWidth <<= 1;
+ curHeight <<= 1;
+ }
+ goto finish;
+ }
+ else
+ {
+ float Xfactor = ( (float)displayWidth / curWidth );
+ float Yfactor = ( (float)displayHeight / curHeight );
+ float scale = MIN( Xfactor, Yfactor );
+
+ curWidth = (int) ( curWidth * scale + 0.35f );
+ curHeight = (int) ( curHeight * scale + 0.35f );
+ clamp( curWidth, 0, displayWidth );
+ clamp( curHeight, 0, displayHeight );
+ goto finish;
+ }
+ }
+ else // we are not locking the aspect ratio...
+ {
+ if ( bIntegralScale )
+ {
+ while ( (curWidth << 1) <= displayWidth )
+ {
+ curWidth <<= 1;
+ }
+ while ( (curHeight << 1) <= displayHeight )
+ {
+ curHeight <<= 1;
+ }
+ goto finish;
+ }
+ else
+ {
+ curWidth = displayWidth;
+ curHeight = displayHeight;
+ goto finish;
+ }
+ }
+ }
+
+
+finish:
+ AssertExitF( displayWidth >= curWidth && displayHeight >= curHeight );
+
+ if ( bCenterVideo )
+ {
+ *pXOffset = ( displayWidth - curWidth ) >> 1;
+ *pYOffset = ( displayHeight - curHeight ) >> 1;
+ }
+ else
+ {
+ *pXOffset = 0;
+ *pYOffset = 0;
+ }
+
+ *pOutputWidth = curWidth;
+ *pOutputHeight = curHeight;
+
+ return true;
+
+}
+
+
+float CVideoCommonServices::GetSystemVolume()
+{
+ ConVarRef volumeConVar( "volume" );
+ float sysVolume = volumeConVar.IsValid() ? volumeConVar.GetFloat() : 1.0f;
+ clamp( sysVolume, 0.0f, 1.0f);
+
+ return sysVolume;
+}
+
+
+
+// ===========================================================================
+// Sets up the state machine to receive messages and poll the keyboard
+// while a full-screen video is playing
+// ===========================================================================
+VideoResult_t CVideoCommonServices::InitFullScreenPlaybackInputHandler( VideoPlaybackFlags_t playbackFlags, float forcedMinTime, bool windowed )
+{
+ // already initialized?
+ if ( m_bInputHandlerInitialized )
+ {
+ WarningAssert( "called twice" );
+ return VideoResult::OPERATION_ALREADY_PERFORMED;
+ }
+
+#ifdef WIN32
+ // We need to be able to poll the state of the input device, but we're not completely setup yet, so this spoofs the ability
+ HINSTANCE m_UserDLLhInst = LoadLibrary( "user32.dll" );
+ if ( m_UserDLLhInst == NULL )
+ {
+ return VideoResult::SYSTEM_ERROR_OCCURED;
+ }
+
+ s_pfnGetAsyncKeyState = (GetAsyncKeyStateFn_t) GetProcAddress( m_UserDLLhInst, "GetAsyncKeyState" );
+ if ( s_pfnGetAsyncKeyState == NULL )
+ {
+ FreeLibrary( m_UserDLLhInst );
+ return VideoResult::SYSTEM_ERROR_OCCURED;
+ }
+
+#endif
+
+ // save off playback options
+ m_playbackFlags = playbackFlags;
+ m_forcedMinTime = forcedMinTime;
+ m_bWindowed = windowed;
+
+ // process the pause and abort options
+ m_bScanAll = ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::PAUSE_ON_ANY_KEY | VideoPlaybackFlags::ABORT_ON_ANY_KEY );
+
+ m_bScanEsc = m_bScanAll || ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::PAUSE_ON_ESC | VideoPlaybackFlags::ABORT_ON_ESC );
+ m_bScanReturn = m_bScanAll || ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::PAUSE_ON_RETURN | VideoPlaybackFlags::ABORT_ON_RETURN );
+ m_bScanSpace = m_bScanAll || ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::PAUSE_ON_SPACE | VideoPlaybackFlags::ABORT_ON_SPACE );
+
+ m_bPauseEnabled = ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::PAUSE_ON_ESC | VideoPlaybackFlags::PAUSE_ON_RETURN | VideoPlaybackFlags::PAUSE_ON_SPACE | VideoPlaybackFlags::PAUSE_ON_ANY_KEY );
+ m_bAbortEnabled = ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::ABORT_ON_ESC | VideoPlaybackFlags::ABORT_ON_RETURN | VideoPlaybackFlags::ABORT_ON_SPACE | VideoPlaybackFlags::ABORT_ON_ANY_KEY );
+
+ // Setup the scan options
+ m_bEscLast = false;
+ m_bReturnLast = false;
+ m_bSpaceLast = false;
+
+ // Other Movie playback state init
+ m_bForceMinPlayTime = BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::FORCE_MIN_PLAY_TIME ) && ( forcedMinTime > 0.0f );
+
+ // Note the start time
+ m_StartTime = Plat_FloatTime();
+
+ // and we're on
+ m_bInputHandlerInitialized = true;
+
+ return VideoResult::SUCCESS;
+}
+
+
+// ===========================================================================
+// Pumps the message loops and checks for a supported event
+// returns true if there is an event to check
+// ===========================================================================
+bool CVideoCommonServices::ProcessFullScreenInput( bool &bAbortEvent, bool &bPauseEvent, bool &bQuitEvent )
+{
+
+ bAbortEvent = false;
+ bPauseEvent = false;
+ bQuitEvent = false;
+
+ if ( !m_bInputHandlerInitialized )
+ {
+ WarningAssert( "Not Initialized to call" );
+ return false;
+ }
+
+
+ // Pump OS Messages
+#if defined( WIN32 )
+ MSG msg;
+ while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
+ {
+ // did we get a quit message?
+ if ( msg.message == WM_QUIT )
+ {
+ ::PostQuitMessage( msg.wParam );
+ return true;
+ }
+
+ // todo - look for alt-tab events, etc?
+
+ TranslateMessage( &msg );
+ DispatchMessage( &msg );
+ }
+ // Escape, return, or space stops or pauses the playback
+ bool bEscPressed = ( m_bScanEsc ) ? ( s_pfnGetAsyncKeyState( VK_ESCAPE ) & 0x8000 ) != 0 : false;
+ bool bReturnPressed = ( m_bScanReturn ) ? ( s_pfnGetAsyncKeyState( VK_RETURN ) & 0x8000 ) != 0 : false;
+ bool bSpacePressed = ( m_bScanSpace ) ? ( s_pfnGetAsyncKeyState( VK_SPACE ) & 0x8000 ) != 0 : false;
+#elif defined(OSX)
+ g_pLauncherMgr->PumpWindowsMessageLoop();
+ // Escape, return, or space stops or pauses the playback
+ bool bEscPressed = ( m_bScanEsc ) ? CGEventSourceKeyState( kCGEventSourceStateCombinedSessionState, kVK_Escape ) : false;
+ bool bReturnPressed = ( m_bScanReturn ) ? CGEventSourceKeyState( kCGEventSourceStateCombinedSessionState, kVK_Return ) : false;
+ bool bSpacePressed = ( m_bScanSpace ) ? CGEventSourceKeyState( kCGEventSourceStateCombinedSessionState, kVK_Space ) : false;
+#elif defined(LINUX)
+ g_pLauncherMgr->PumpWindowsMessageLoop();
+
+ // Escape, return, or space stops or pauses the playback
+ bool bEscPressed = false;
+ bool bReturnPressed = false;
+ bool bSpacePressed = false;
+
+ g_pLauncherMgr->PeekAndRemoveKeyboardEvents( &bEscPressed, &bReturnPressed, &bSpacePressed );
+#endif
+
+ // Manual debounce of the keys, only interested in unpressed->pressed transitions
+ bool bEscEvent = ( bEscPressed != m_bEscLast ) && bEscPressed;
+ bool bReturnEvent = ( bReturnPressed != m_bReturnLast ) && bReturnPressed;
+ bool bSpaceEvent = ( bSpacePressed != m_bSpaceLast ) && bSpacePressed;
+ bool bAnyKeyEvent = bEscEvent || bReturnEvent || bSpaceEvent;
+
+ m_bEscLast = bEscPressed;
+ m_bReturnLast = bReturnPressed;
+ m_bSpaceLast = bSpacePressed;
+
+ // Are we forcing a minimum playback time?
+ // if so, no Abort or Pause events until the necessary time has elasped
+ if ( m_bForceMinPlayTime )
+ {
+ double elapsedTime = Plat_FloatTime() - m_StartTime;
+ if ( (float) elapsedTime > m_forcedMinTime )
+ {
+ m_bForceMinPlayTime = false; // turn off forced minimum
+ }
+ }
+
+ // any key events to check? ( provided minimum enforced playback has occurred )
+ if ( m_bForceMinPlayTime == false && bAnyKeyEvent )
+ {
+ // check for aborting the movie
+ if ( m_bAbortEnabled )
+ {
+ bAbortEvent = ( bAnyKeyEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::ABORT_ON_ANY_KEY ) ) ||
+ ( bEscEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::ABORT_ON_ESC ) ) ||
+ ( bReturnEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::ABORT_ON_RETURN ) ) ||
+ ( bSpaceEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::ABORT_ON_SPACE ) );
+
+ }
+
+ // check for pausing the movie?
+ if ( m_bPauseEnabled )
+ {
+ bPauseEvent = ( bAnyKeyEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::PAUSE_ON_ANY_KEY ) ) ||
+ ( bEscEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::PAUSE_ON_ESC ) ) ||
+ ( bReturnEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::PAUSE_ON_RETURN ) ) ||
+ ( bSpaceEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::PAUSE_ON_SPACE ) );
+ }
+ }
+
+ // notify if any events triggered
+ return ( bAbortEvent || bPauseEvent );
+}
+
+
+
+
+VideoResult_t CVideoCommonServices::TerminateFullScreenPlaybackInputHandler()
+{
+
+ if ( !m_bInputHandlerInitialized )
+ {
+ WarningAssert( "Not Initialized to call" );
+ return VideoResult::OPERATION_OUT_OF_SEQUENCE;
+ }
+
+#if defined ( WIN32 )
+ FreeLibrary( s_UserDLLhInst ); // and free the dll we needed
+#endif
+
+ ResetInputHandlerState();
+
+ return VideoResult::SUCCESS;
+
+}