Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1464 lines
44 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "filesystem.h"
  7. #include "tier1/strtools.h"
  8. #include "tier1/utllinkedlist.h"
  9. #include "tier1/KeyValues.h"
  10. #include "materialsystem/imaterial.h"
  11. #include "materialsystem/imaterialsystem.h"
  12. #include "materialsystem/MaterialSystemUtil.h"
  13. #include "materialsystem/itexture.h"
  14. #include "vgui/ILocalize.h"
  15. #include "vtf/vtf.h"
  16. #include "pixelwriter.h"
  17. #include "tier3/tier3.h"
  18. #include "platform.h"
  19. #include "videoservices.h"
  20. #include "video_macros.h"
  21. #include "tier0/memdbgon.h"
  22. #if defined( WIN32 )
  23. #include <windows.h>
  24. #elif defined( OSX )
  25. #include <Carbon/Carbon.h>
  26. #endif
  27. #if defined( USE_SDL )
  28. #include "SDL.h"
  29. #include "appframework/ilaunchermgr.h"
  30. #endif
  31. //-----------------------------------------------------------------------------
  32. // Platform specific video system controls & definitions
  33. //-----------------------------------------------------------------------------
  34. enum EPlatform_t
  35. {
  36. PLATFORM_NONE = 0,
  37. PLATFORM_WIN32 = 0x01,
  38. PLATFORM_OSX = 0x02,
  39. PLATFORM_XBOX_360 = 0x04,
  40. PLATFORM_PS3 = 0x08,
  41. PLATFORM_LINUX = 0x10
  42. };
  43. DEFINE_ENUM_BITWISE_OPERATORS( EPlatform_t );
  44. #if defined( IS_WINDOWS_PC )
  45. const EPlatform_t thisPlatform = PLATFORM_WIN32;
  46. #elif defined( OSX )
  47. const EPlatform_t thisPlatform = PLATFORM_OSX;
  48. #elif defined( _X360 )
  49. const EPlatform_t thisPlatform = PLATFORM_XBOX_360;
  50. #elif defined( _PS3 )
  51. const EPlatform_t thisPlatform = PLATFORM_PS3;
  52. #elif defined ( _LINUX )
  53. const EPlatform_t thisPlatform = PLATFORM_LINUX;
  54. #else
  55. #error "UNABLE TO DETERMINE PLATFORM"
  56. #endif
  57. #if defined( OSX ) || defined( LINUX )
  58. ILauncherMgr *g_pLauncherMgr = NULL;
  59. #endif
  60. struct VideoSystemInfo_t
  61. {
  62. VideoSystem_t m_SystemID;
  63. EPlatform_t m_Platforms;
  64. const char *m_pModuleName;
  65. const char *m_pInterfaceName;
  66. };
  67. static VideoSystemInfo_t s_VideoAppSystems[] =
  68. {
  69. { VideoSystem::QUICKTIME, PLATFORM_WIN32 | PLATFORM_OSX, "video_quicktime", VIDEO_SUBSYSTEM_INTERFACE_VERSION },
  70. { VideoSystem::BINK, PLATFORM_WIN32 | PLATFORM_OSX | PLATFORM_XBOX_360 | PLATFORM_LINUX, "video_bink", VIDEO_SUBSYSTEM_INTERFACE_VERSION },
  71. //{ VideoSystem::AVI, PLATFORM_WIN32, "avi", VIDEO_SUBSYSTEM_INTERFACE_VERSION },
  72. //{ VideoSystem::WMV, PLATFORM_WIN32, "wmv", VIDEO_SUBSYSTEM_INTERFACE_VERSION },
  73. { VideoSystem::WEBM, PLATFORM_LINUX, "video_webm", VIDEO_SUBSYSTEM_INTERFACE_VERSION },
  74. { VideoSystem::NONE, PLATFORM_NONE, nullptr, nullptr } // Required to terminate the list
  75. };
  76. //-----------------------------------------------------------------------------
  77. // Setup Singleton for accessing Valve Video Services
  78. //-----------------------------------------------------------------------------
  79. static CValveVideoServices g_VALVeVIDEO;
  80. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CValveVideoServices, IVideoServices, VIDEO_SERVICES_INTERFACE_VERSION, g_VALVeVIDEO );
  81. static CVideoCommonServices g_VALVEVIDEOCommon;
  82. //-----------------------------------------------------------------------------
  83. // Valve Video Services implementation
  84. //-----------------------------------------------------------------------------
  85. CValveVideoServices::CValveVideoServices() :
  86. m_nInstalledSystems( 0 ),
  87. m_bInitialized( false ),
  88. m_nMaterialCount( 0 )
  89. {
  90. for ( int i = 0; i < VideoSystem::VIDEO_SYSTEM_COUNT; i++ )
  91. {
  92. m_VideoSystemModule[i] = nullptr;
  93. m_VideoSystems[i] = nullptr;
  94. m_VideoSystemType[i] = VideoSystem::NONE;
  95. m_VideoSystemFeatures[i] = VideoSystemFeature::NO_FEATURES;
  96. }
  97. }
  98. CValveVideoServices::~CValveVideoServices()
  99. {
  100. DisconnectVideoLibraries( );
  101. }
  102. bool CValveVideoServices::Connect( CreateInterfaceFn factory )
  103. {
  104. if ( !BaseClass::Connect( factory ) )
  105. {
  106. return false;
  107. }
  108. if ( g_pFullFileSystem == nullptr || materials == nullptr )
  109. {
  110. Msg( "Valve Video Services unable to connect due to missing dependent system\n" );
  111. return false;
  112. }
  113. #if defined( USE_SDL )
  114. g_pLauncherMgr = (ILauncherMgr *)factory( SDLMGR_INTERFACE_VERSION, NULL );
  115. #endif
  116. if ( !ConnectVideoLibraries( factory ) )
  117. {
  118. return false;
  119. }
  120. return ( true );
  121. }
  122. void CValveVideoServices::Disconnect()
  123. {
  124. DisconnectVideoLibraries();
  125. }
  126. void* CValveVideoServices::QueryInterface( const char *pInterfaceName )
  127. {
  128. if ( Q_strncmp( pInterfaceName, VIDEO_SERVICES_INTERFACE_VERSION, Q_strlen( VIDEO_SERVICES_INTERFACE_VERSION ) + 1) == 0 )
  129. {
  130. return (IVideoServices*) this;
  131. }
  132. return nullptr;
  133. }
  134. bool CValveVideoServices::ConnectVideoLibraries( CreateInterfaceFn factory )
  135. {
  136. // Don't connect twice..
  137. AssertExitF( m_bInitialized == false );
  138. int n = 0;
  139. while ( IS_NOT_EMPTY( s_VideoAppSystems[n].m_pModuleName ) && s_VideoAppSystems[n].m_SystemID != VideoSystem::NONE )
  140. {
  141. if (BITFLAGS_SET( s_VideoAppSystems[n].m_Platforms, thisPlatform ) )
  142. {
  143. bool success = false;
  144. CSysModule *pModule = Sys_LoadModule(s_VideoAppSystems[n].m_pModuleName );
  145. if( pModule != nullptr )
  146. {
  147. CreateInterfaceFn fn = Sys_GetFactory( pModule );
  148. if ( fn != nullptr )
  149. {
  150. IVideoSubSystem *pVideoSystem = (IVideoSubSystem*) fn( s_VideoAppSystems[n].m_pInterfaceName, NULL );
  151. if ( pVideoSystem != nullptr && pVideoSystem->Connect( factory ) )
  152. {
  153. if ( pVideoSystem->InitializeVideoSystem( &g_VALVEVIDEOCommon ) )
  154. {
  155. int slotNum = (int) pVideoSystem->GetSystemID();
  156. if ( IS_IN_RANGECOUNT( slotNum, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ) )
  157. {
  158. Assert( m_VideoSystemModule[slotNum] == nullptr );
  159. m_VideoSystemModule[slotNum] = pModule;
  160. m_VideoSystems[slotNum] = pVideoSystem;
  161. m_nInstalledSystems++;
  162. success = true;
  163. }
  164. }
  165. }
  166. }
  167. if ( success == false )
  168. {
  169. 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 );
  170. Sys_UnloadModule( pModule );
  171. }
  172. }
  173. }
  174. n++;
  175. }
  176. // now we query each video system for its capabilities, and supported file extensions
  177. for ( int i = VideoSystem::VIDEO_SYSTEM_FIRST; i < VideoSystem::VIDEO_SYSTEM_COUNT; i++ )
  178. {
  179. IVideoSubSystem *pSubSystem = m_VideoSystems[i];
  180. if ( pSubSystem != nullptr )
  181. {
  182. m_VideoSystemType[i] = pSubSystem->GetSystemID();
  183. m_VideoSystemFeatures[i] = pSubSystem->GetSupportedFeatures();
  184. // get every file extension it handles, and the info about it
  185. int eCount = pSubSystem->GetSupportedFileExtensionCount();
  186. Assert( eCount > 0 );
  187. for ( int n = 0; n < eCount; n++ )
  188. {
  189. VideoFileExtensionInfo_t extInfoRec;
  190. extInfoRec.m_FileExtension = pSubSystem->GetSupportedFileExtension( n );
  191. extInfoRec.m_VideoSubSystem = pSubSystem->GetSystemID();
  192. extInfoRec.m_VideoFeatures = pSubSystem->GetSupportedFileExtensionFeatures( n );
  193. AssertPtr( extInfoRec.m_FileExtension );
  194. m_ExtInfo.AddToTail( extInfoRec );
  195. }
  196. }
  197. }
  198. m_bInitialized = true;
  199. return true;
  200. }
  201. bool CValveVideoServices::DisconnectVideoLibraries()
  202. {
  203. if ( !m_bInitialized )
  204. {
  205. return false;
  206. }
  207. // free up any objects/resources still out there
  208. DestroyAllVideoInterfaces();
  209. for ( int i = 0; i < VideoSystem::VIDEO_SYSTEM_COUNT; i++ )
  210. {
  211. if ( m_VideoSystems[i] != nullptr )
  212. {
  213. m_VideoSystems[i]->ShutdownVideoSystem();
  214. m_VideoSystems[i]->Disconnect();
  215. m_VideoSystems[i] = nullptr;
  216. }
  217. if ( m_VideoSystemModule[i] != nullptr )
  218. {
  219. Sys_UnloadModule( m_VideoSystemModule[i] );
  220. m_VideoSystemModule[i] = nullptr;
  221. }
  222. m_VideoSystemType[i] = VideoSystem::NONE;
  223. m_VideoSystemFeatures[i] = VideoSystemFeature::NO_FEATURES;
  224. }
  225. m_bInitialized = false;
  226. return true;
  227. }
  228. int CValveVideoServices::DestroyAllVideoInterfaces()
  229. {
  230. int n = m_RecorderList.Count() + m_MaterialList.Count();
  231. for ( int i = m_RecorderList.Count() -1; i >= 0; i-- )
  232. {
  233. DestroyVideoRecorder( (IVideoRecorder*) m_RecorderList[i].m_pObject );
  234. }
  235. for ( int i = m_MaterialList.Count() -1; i >= 0; i-- )
  236. {
  237. DestroyVideoMaterial( (IVideoMaterial*) m_MaterialList[i].m_pObject );
  238. }
  239. return n;
  240. }
  241. InitReturnVal_t CValveVideoServices::Init()
  242. {
  243. InitReturnVal_t nRetVal = BaseClass::Init();
  244. if ( nRetVal != INIT_OK )
  245. {
  246. return nRetVal;
  247. }
  248. // Initialize all loaded subsystems
  249. for ( int n = VideoSystem::VIDEO_SYSTEM_FIRST; n < VideoSystem::VIDEO_SYSTEM_COUNT; n++ )
  250. {
  251. if ( m_VideoSystems[n] != nullptr )
  252. {
  253. nRetVal = m_VideoSystems[n]->Init();
  254. if ( nRetVal != INIT_OK )
  255. {
  256. return nRetVal;
  257. }
  258. }
  259. }
  260. return INIT_OK;
  261. }
  262. void CValveVideoServices::Shutdown()
  263. {
  264. DestroyAllVideoInterfaces();
  265. // Shutdown all loaded subsystems
  266. for ( int n = VideoSystem::VIDEO_SYSTEM_FIRST; n < VideoSystem::VIDEO_SYSTEM_COUNT; n++ )
  267. {
  268. if ( m_VideoSystems[n] != nullptr )
  269. {
  270. m_VideoSystems[n]->Shutdown();
  271. }
  272. }
  273. BaseClass::Shutdown();
  274. }
  275. // ===========================================================================
  276. // Inherited from IVideoServices
  277. // ===========================================================================
  278. // Query the available video systems
  279. int CValveVideoServices::GetAvailableVideoSystemCount()
  280. {
  281. return m_nInstalledSystems;
  282. }
  283. // returns the enumerated video system, *IF* it is installed and working
  284. VideoSystem_t CValveVideoServices::GetAvailableVideoSystem( int n )
  285. {
  286. if ( n< 0 || n >= m_nInstalledSystems )
  287. {
  288. return VideoSystem::NONE;
  289. }
  290. for ( int i = VideoSystem::VIDEO_SYSTEM_FIRST, c = 0; i < VideoSystem::VIDEO_SYSTEM_COUNT; i++ )
  291. {
  292. if ( m_VideoSystems[i] != nullptr )
  293. {
  294. if ( c == n )
  295. {
  296. return m_VideoSystemType[i];
  297. }
  298. c++;
  299. }
  300. }
  301. return VideoSystem::NONE;
  302. }
  303. // ===========================================================================
  304. // returns the index for the video system...
  305. // ... provided that system is installed and available to do something
  306. // ===========================================================================
  307. int CValveVideoServices::GetIndexForSystem( VideoSystem_t n )
  308. {
  309. if ( n >= VideoSystem::VIDEO_SYSTEM_FIRST && n < VideoSystem::VIDEO_SYSTEM_COUNT && m_nInstalledSystems > 0 )
  310. {
  311. int i = (int) n;
  312. if ( m_VideoSystems[i] != nullptr && m_VideoSystemFeatures[i] != VideoSystemFeature::NO_FEATURES )
  313. {
  314. return i;
  315. }
  316. }
  317. return SYSTEM_NOT_FOUND;
  318. }
  319. VideoSystem_t CValveVideoServices::GetSystemForIndex( int n )
  320. {
  321. if ( n >= VideoSystem::VIDEO_SYSTEM_FIRST && n < VideoSystem::VIDEO_SYSTEM_COUNT && m_nInstalledSystems > 0 )
  322. {
  323. if ( m_VideoSystems[n] != nullptr && m_VideoSystemFeatures[n] != VideoSystemFeature::NO_FEATURES )
  324. {
  325. return (VideoSystem_t) n;
  326. }
  327. }
  328. return VideoSystem::NONE;
  329. }
  330. // ===========================================================================
  331. // video system query functions
  332. // ===========================================================================
  333. bool CValveVideoServices::IsVideoSystemAvailable( VideoSystem_t videoSystem )
  334. {
  335. int n = GetIndexForSystem( videoSystem );
  336. return ( n != SYSTEM_NOT_FOUND ) ? true : false;
  337. }
  338. VideoSystemStatus_t CValveVideoServices::GetVideoSystemStatus( VideoSystem_t videoSystem )
  339. {
  340. int n = GetIndexForSystem( videoSystem );
  341. return ( n!= SYSTEM_NOT_FOUND ) ? m_VideoSystems[n]->GetSystemStatus() : VideoSystemStatus::NOT_INSTALLED;
  342. }
  343. VideoSystemFeature_t CValveVideoServices::GetVideoSystemFeatures( VideoSystem_t videoSystem )
  344. {
  345. int n = GetIndexForSystem( videoSystem );
  346. return ( n!= SYSTEM_NOT_FOUND ) ? m_VideoSystemFeatures[n] : VideoSystemFeature::NO_FEATURES;
  347. }
  348. const char *CValveVideoServices::GetVideoSystemName( VideoSystem_t videoSystem )
  349. {
  350. int n = GetIndexForSystem( videoSystem );
  351. return ( n!= SYSTEM_NOT_FOUND ) ? m_VideoSystems[n]->GetVideoSystemName() : nullptr;
  352. }
  353. VideoSystem_t CValveVideoServices::FindNextSystemWithFeature( VideoSystemFeature_t features, VideoSystem_t startAfter )
  354. {
  355. if ( ( features & VideoSystemFeature::ALL_VALID_FEATURES ) == 0 )
  356. {
  357. return VideoSystem::NONE;
  358. }
  359. int start = VideoSystem::VIDEO_SYSTEM_FIRST;
  360. if ( startAfter != VideoSystem::NONE && IS_IN_RANGECOUNT( startAfter, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ) )
  361. {
  362. start = (int) startAfter;
  363. }
  364. for ( int i = start; i < VideoSystem::VIDEO_SYSTEM_COUNT; i++ )
  365. {
  366. if ( m_VideoSystems[i] != nullptr && BITFLAGS_SET( m_VideoSystemFeatures[i], features ) )
  367. {
  368. return (VideoSystem_t) i;
  369. }
  370. }
  371. return VideoSystem::NONE;
  372. }
  373. // ===========================================================================
  374. // video services status functions
  375. // ===========================================================================
  376. VideoResult_t CValveVideoServices::GetLastResult()
  377. {
  378. return m_LastResult;
  379. }
  380. VideoResult_t CValveVideoServices::SetResult( VideoResult_t resultCode )
  381. {
  382. m_LastResult = resultCode;
  383. return resultCode;
  384. }
  385. // ===========================================================================
  386. // deal with video file extensions and video system mappings
  387. // ===========================================================================
  388. int CValveVideoServices::GetSupportedFileExtensionCount( VideoSystem_t videoSystem )
  389. {
  390. int n = GetIndexForSystem( videoSystem );
  391. return ( n == SYSTEM_NOT_FOUND ) ? 0 : m_VideoSystems[n]->GetSupportedFileExtensionCount();
  392. }
  393. const char *CValveVideoServices::GetSupportedFileExtension( VideoSystem_t videoSystem, int extNum )
  394. {
  395. int n = GetIndexForSystem( videoSystem );
  396. int c = ( n == SYSTEM_NOT_FOUND ) ? 0 : m_VideoSystems[n]->GetSupportedFileExtensionCount();;
  397. return ( extNum < 0 || extNum >= c ) ? nullptr : m_VideoSystems[n]->GetSupportedFileExtension( extNum );
  398. }
  399. VideoSystemFeature_t CValveVideoServices::GetSupportedFileExtensionFeatures( VideoSystem_t videoSystem, int extNum )
  400. {
  401. int n = GetIndexForSystem( videoSystem );
  402. int c = ( n == SYSTEM_NOT_FOUND ) ? 0 : m_VideoSystems[n]->GetSupportedFileExtensionCount();
  403. return ( extNum < 0 || extNum >= c ) ? VideoSystemFeature::NO_FEATURES : m_VideoSystems[n]->GetSupportedFileExtensionFeatures( extNum );
  404. }
  405. VideoSystem_t CValveVideoServices::LocateVideoSystemForPlayingFile( const char *pFileName, VideoSystemFeature_t playMode )
  406. {
  407. SetResult( VideoResult::BAD_INPUT_PARAMETERS );
  408. AssertExitV( IS_NOT_EMPTY( pFileName ), VideoSystem::NONE );
  409. VideoSystem_t theSystem = LocateSystemAndFeaturesForFileName( pFileName, nullptr, playMode );
  410. SetResult( VideoResult::SUCCESS );
  411. return theSystem;
  412. }
  413. // ===========================================================================
  414. // Given a video file name, possibly with a set extension, locate the file
  415. // or a suitable substitute that is playable on the current system
  416. // ===========================================================================
  417. VideoResult_t CValveVideoServices::LocatePlayableVideoFile( const char *pSearchFileName, const char *pPathID, VideoSystem_t *pPlaybackSystem, char *pPlaybackFileName, int fileNameMaxLen, VideoSystemFeature_t playMode )
  418. {
  419. AssertExitV( IS_NOT_EMPTY( pSearchFileName ) || pPlaybackSystem == nullptr || pPlaybackSystem == nullptr || fileNameMaxLen <= 0, SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
  420. VideoResult_t Status = ResolveToPlayableVideoFile( pSearchFileName, pPathID, VideoSystem::DETERMINE_FROM_FILE_EXTENSION, playMode,
  421. true, pPlaybackFileName, fileNameMaxLen, pPlaybackSystem );
  422. return SetResult( Status );
  423. }
  424. // ===========================================================================
  425. // Create/destroy a video material
  426. // ===========================================================================
  427. IVideoMaterial* CValveVideoServices::CreateVideoMaterial( const char *pMaterialName, const char *pVideoFileName, const char *pPathID, VideoPlaybackFlags_t playbackFlags, VideoSystem_t videoSystem, bool PlayAlternateIfNotAvailable )
  428. {
  429. SetResult( VideoResult::BAD_INPUT_PARAMETERS );
  430. AssertExitV( IS_NOT_EMPTY( pVideoFileName ), nullptr );
  431. AssertExitV( videoSystem == VideoSystem::DETERMINE_FROM_FILE_EXTENSION || IS_IN_RANGECOUNT( videoSystem, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ), nullptr );
  432. // We need to resolve the filename and video system
  433. char ResolvedFilePath[MAX_PATH];
  434. VideoSystem_t actualVideoSystem = videoSystem;
  435. VideoResult_t Status = ResolveToPlayableVideoFile( pVideoFileName, pPathID, videoSystem, VideoSystemFeature::PLAY_VIDEO_FILE_IN_MATERIAL, PlayAlternateIfNotAvailable,
  436. ResolvedFilePath, sizeof(ResolvedFilePath), &actualVideoSystem );
  437. SetResult( Status );
  438. if ( Status != VideoResult::SUCCESS )
  439. {
  440. return nullptr;
  441. }
  442. int sysIndex = GetIndexForSystem( actualVideoSystem );
  443. if ( sysIndex == SYSTEM_NOT_FOUND )
  444. {
  445. SetResult( VideoResult::SYSTEM_ERROR_OCCURED );
  446. return nullptr;
  447. }
  448. // Create the video material
  449. IVideoMaterial *pMaterial = m_VideoSystems[sysIndex]->CreateVideoMaterial( pMaterialName, ResolvedFilePath, playbackFlags );
  450. // Update our list, and return
  451. if ( pMaterial != nullptr )
  452. {
  453. CActiveVideoObjectRecord_t info;
  454. info.m_pObject = pMaterial;
  455. info.m_VideoSystem = sysIndex;
  456. m_MaterialList.AddToTail( info );
  457. }
  458. SetResult( m_VideoSystems[sysIndex]->GetLastResult() );
  459. return pMaterial;
  460. }
  461. VideoResult_t CValveVideoServices::DestroyVideoMaterial( IVideoMaterial* pVideoMaterial )
  462. {
  463. AssertPtrExitV( pVideoMaterial, SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
  464. for ( int i = 0; i < m_MaterialList.Count(); i++ )
  465. {
  466. if ( m_MaterialList[i].m_pObject == pVideoMaterial )
  467. {
  468. VideoResult_t Status = m_VideoSystems[ m_MaterialList[i].m_VideoSystem ]->DestroyVideoMaterial( pVideoMaterial );
  469. m_MaterialList.Remove( i );
  470. return SetResult( Status );
  471. }
  472. }
  473. return SetResult( VideoResult::RECORDER_NOT_FOUND );
  474. return VideoResult::SUCCESS;
  475. }
  476. int CValveVideoServices::GetUniqueMaterialID()
  477. {
  478. m_nMaterialCount++;
  479. return m_nMaterialCount;
  480. }
  481. // ===========================================================================
  482. // Query availabilily of codec for encoding video
  483. // ===========================================================================
  484. VideoResult_t CValveVideoServices::IsRecordCodecAvailable( VideoSystem_t videoSystem, VideoEncodeCodec_t codec )
  485. {
  486. AssertExitV( codec >= VideoEncodeCodec::DEFAULT_CODEC && codec < VideoEncodeCodec::CODEC_COUNT, SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
  487. int n = GetIndexForSystem( videoSystem );
  488. if ( n == SYSTEM_NOT_FOUND )
  489. {
  490. return SetResult( VideoResult::SYSTEM_NOT_AVAILABLE );
  491. }
  492. return m_VideoSystems[n]->CheckCodecAvailability( codec );
  493. }
  494. // ===========================================================================
  495. // Create/destroy a video encoder
  496. // ===========================================================================
  497. IVideoRecorder* CValveVideoServices::CreateVideoRecorder( VideoSystem_t videoSystem )
  498. {
  499. int n = GetIndexForSystem( videoSystem );
  500. if ( n == SYSTEM_NOT_FOUND )
  501. {
  502. SetResult( VideoResult::SYSTEM_NOT_AVAILABLE );
  503. return nullptr;
  504. }
  505. if ( !BITFLAGS_SET( m_VideoSystemFeatures[n], VideoSystemFeature::ENCODE_VIDEO_TO_FILE ) )
  506. {
  507. SetResult( VideoResult::FEATURE_NOT_AVAILABLE );
  508. return nullptr;
  509. }
  510. IVideoRecorder *pRecorder = m_VideoSystems[n]->CreateVideoRecorder();
  511. if ( pRecorder != nullptr )
  512. {
  513. CActiveVideoObjectRecord_t info;
  514. info.m_pObject = pRecorder;
  515. info.m_VideoSystem = n;
  516. m_RecorderList.AddToTail( info );
  517. }
  518. SetResult( m_VideoSystems[n]->GetLastResult() );
  519. return pRecorder;
  520. }
  521. VideoResult_t CValveVideoServices::DestroyVideoRecorder( IVideoRecorder *pVideoRecorder )
  522. {
  523. AssertPtrExitV( pVideoRecorder, SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
  524. for ( int i = 0; i < m_RecorderList.Count(); i++ )
  525. {
  526. if ( m_RecorderList[i].m_pObject == pVideoRecorder )
  527. {
  528. VideoResult_t Status = m_VideoSystems[ m_RecorderList[i].m_VideoSystem ]->DestroyVideoRecorder( pVideoRecorder );
  529. m_RecorderList.Remove( i );
  530. return SetResult( Status );
  531. }
  532. }
  533. return SetResult( VideoResult::RECORDER_NOT_FOUND );
  534. }
  535. // ===========================================================================
  536. // Plays a given video file until it completes or the user aborts
  537. // ===========================================================================
  538. 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 )
  539. {
  540. SetResult( VideoResult::BAD_INPUT_PARAMETERS );
  541. AssertExitV( IS_NOT_EMPTY( pFileName ), VideoResult::BAD_INPUT_PARAMETERS );
  542. AssertExitV( videoSystem == VideoSystem::DETERMINE_FROM_FILE_EXTENSION || IS_IN_RANGECOUNT( videoSystem, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ), VideoResult::BAD_INPUT_PARAMETERS );
  543. char ResolvedFilePath[MAX_PATH];
  544. VideoSystem_t actualVideoSystem = videoSystem;
  545. VideoResult_t Status = ResolveToPlayableVideoFile( pFileName, pPathID, videoSystem, VideoSystemFeature::PLAY_VIDEO_FILE_FULL_SCREEN, PlayAlternateIfNotAvailable,
  546. ResolvedFilePath, sizeof(ResolvedFilePath), &actualVideoSystem );
  547. if ( Status != VideoResult::SUCCESS )
  548. {
  549. return Status;
  550. }
  551. int sysIndex = GetIndexForSystem( actualVideoSystem );
  552. if ( sysIndex != SYSTEM_NOT_FOUND )
  553. {
  554. return SetResult( m_VideoSystems[sysIndex]->PlayVideoFileFullScreen( ResolvedFilePath, mainWindow, windowWidth, windowHeight, desktopWidth, desktopHeight, windowed, forcedMinTime, playbackFlags ) );
  555. }
  556. else
  557. {
  558. return SetResult( VideoResult::SYSTEM_ERROR_OCCURED );
  559. }
  560. }
  561. // ===========================================================================
  562. // Functions to connect sound systems to video systems
  563. // ===========================================================================
  564. VideoResult_t CValveVideoServices::SoundDeviceCommand( VideoSoundDeviceOperation_t operation, void *pDevice, void *pData, VideoSystem_t videoSystem )
  565. {
  566. AssertExitV( IS_IN_RANGECOUNT( operation, 0, VideoSoundDeviceOperation::OPERATION_COUNT ), SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
  567. AssertExitV( videoSystem == VideoSystem::ALL_VIDEO_SYSTEMS || IS_IN_RANGECOUNT( videoSystem, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ), SetResult( VideoResult::BAD_INPUT_PARAMETERS ) );
  568. int startIdx = (int) VideoSystem::VIDEO_SYSTEM_FIRST;
  569. int lastIdx = (int) VideoSystem::VIDEO_SYSTEM_COUNT - 1;
  570. if ( videoSystem != VideoSystem::ALL_VIDEO_SYSTEMS )
  571. {
  572. startIdx = lastIdx = GetIndexForSystem( videoSystem );
  573. if ( startIdx == SYSTEM_NOT_FOUND )
  574. {
  575. return SetResult( VideoResult::SYSTEM_NOT_AVAILABLE );
  576. }
  577. }
  578. VideoResult_t result = VideoResult::SYSTEM_NOT_AVAILABLE;
  579. for ( int i = startIdx; i <= lastIdx; i++ )
  580. {
  581. int n = GetIndexForSystem( (VideoSystem_t) i );
  582. if ( n != SYSTEM_NOT_FOUND )
  583. {
  584. result = m_VideoSystems[n]->VideoSoundDeviceCMD( operation, pDevice, pData );
  585. }
  586. }
  587. return SetResult( result );
  588. }
  589. // ===========================================================================
  590. // Sets the sound devices that the video will decode to
  591. // ===========================================================================
  592. const wchar_t *CValveVideoServices::GetCodecName( VideoEncodeCodec_t nCodec )
  593. {
  594. static const char *s_pCodecLookup[VideoEncodeCodec::CODEC_COUNT] =
  595. {
  596. "#Codec_MPEG2",
  597. "#Codec_MPEG4",
  598. "#Codec_H261",
  599. "#Codec_H263",
  600. "#Codec_H264",
  601. "#Codec_MJPEG_A",
  602. "#Codec_MJPEG_B",
  603. "#Codec_SORENSON3",
  604. "#Codec_CINEPACK",
  605. "#Codec_WEBM",
  606. };
  607. if ( nCodec < 0 || nCodec >= VideoEncodeCodec::CODEC_COUNT )
  608. {
  609. AssertMsg( 0, "Invalid codec in CValveVideoServices::GetCodecName()" );
  610. return NULL;
  611. }
  612. return g_pVGuiLocalize->Find( s_pCodecLookup[ nCodec ] );
  613. }
  614. // ===========================================================================
  615. // Functions to determine which file and video system to use
  616. // ===========================================================================
  617. VideoResult_t CValveVideoServices::ResolveToPlayableVideoFile( const char *pFileName, const char *pPathID, VideoSystem_t videoSystem, VideoSystemFeature_t requiredFeature,
  618. bool PlayAlternateIfNotAvailable, char *pResolvedFileName, int resolvedFileNameMaxLen, VideoSystem_t *pResolvedVideoSystem )
  619. {
  620. SetResult( VideoResult::BAD_INPUT_PARAMETERS );
  621. AssertExitV( IS_NOT_EMPTY( pFileName ), VideoResult::BAD_INPUT_PARAMETERS );
  622. AssertExitV( videoSystem == VideoSystem::DETERMINE_FROM_FILE_EXTENSION || IS_IN_RANGECOUNT( videoSystem, VideoSystem::VIDEO_SYSTEM_FIRST, VideoSystem::VIDEO_SYSTEM_COUNT ), VideoResult::BAD_INPUT_PARAMETERS );
  623. AssertExitV( requiredFeature != VideoSystemFeature::NO_FEATURES, VideoResult::BAD_INPUT_PARAMETERS );
  624. AssertExitV( pResolvedFileName != nullptr && resolvedFileNameMaxLen > 0 && pResolvedVideoSystem != nullptr, VideoResult::BAD_INPUT_PARAMETERS );
  625. // clear results should we return failure
  626. pResolvedFileName[0] = nullchar;
  627. *pResolvedVideoSystem = VideoSystem::NONE;
  628. int sysIdx = SYSTEM_NOT_FOUND;
  629. VideoSystemFeature_t sysFeatures = VideoSystemFeature::NO_FEATURES;
  630. // check the file extension to see if it specifies searching for any compatible video files
  631. // if so, override a couple input values
  632. if ( !IsMatchAnyExtension( pFileName ) )
  633. {
  634. goto search_for_video;
  635. }
  636. // is the requested video system available?
  637. // We start with either the specified video system.. OR.. we choose the system based on the file extension
  638. // Get the system and if it's valid, it's available features
  639. if ( videoSystem != VideoSystem::DETERMINE_FROM_FILE_EXTENSION )
  640. {
  641. sysIdx = GetIndexForSystem( videoSystem ); // Caller specified the video system
  642. sysFeatures = ( sysIdx != SYSTEM_NOT_FOUND ) ? m_VideoSystemFeatures[sysIdx] : VideoSystemFeature::NO_FEATURES;
  643. }
  644. else
  645. {
  646. // We need to determine the system to use based on filename
  647. sysIdx = GetIndexForSystem( LocateSystemAndFeaturesForFileName( pFileName, &sysFeatures, requiredFeature ) );
  648. }
  649. // if we don't have a system to play this video.. and aren't allowed to look for an alternative...
  650. if ( sysIdx == SYSTEM_NOT_FOUND && PlayAlternateIfNotAvailable == false )
  651. {
  652. return SetResult( VideoResult::VIDEO_SYSTEM_NOT_FOUND ); // return failure
  653. }
  654. char ActualFilePath[MAX_PATH];
  655. // Examine the requested of inferred video system to see if it can do what we want,
  656. // and if so, see if the corresponding file is actually found (we support search paths)
  657. // Decision Path for when we have a preferred/specified video system specified to use
  658. if ( sysIdx != SYSTEM_NOT_FOUND )
  659. {
  660. bool fileFound = false;
  661. // if the request system can do the task, see if we can find the file as supplied by the caller
  662. if ( BITFLAGS_SET( sysFeatures, requiredFeature ) )
  663. {
  664. if ( V_IsAbsolutePath( pFileName ) )
  665. {
  666. V_strncpy( ActualFilePath, pFileName, sizeof( ActualFilePath ) );
  667. fileFound = g_pFullFileSystem->FileExists( pFileName, nullptr );
  668. }
  669. else
  670. {
  671. fileFound = ( g_pFullFileSystem->RelativePathToFullPath( pFileName, pPathID, ActualFilePath, sizeof( ActualFilePath ) ) != nullptr );
  672. }
  673. }
  674. else // The specified video system does not support this (required) feature
  675. {
  676. // if we can't search for an alternative file, tell them we don't support this
  677. if ( !PlayAlternateIfNotAvailable )
  678. {
  679. return SetResult( VideoResult::FEATURE_NOT_AVAILABLE );
  680. }
  681. }
  682. // We found the specified file, and the video system has the feature support
  683. if ( fileFound )
  684. {
  685. // copy the resolved filename and system and report success
  686. V_strncpy( pResolvedFileName, ActualFilePath, resolvedFileNameMaxLen );
  687. *pResolvedVideoSystem = GetSystemForIndex( sysIdx );
  688. return SetResult( VideoResult::SUCCESS );
  689. }
  690. // ok, we have the feature support but didn't find the file to use...
  691. if ( !PlayAlternateIfNotAvailable )
  692. {
  693. // if we can't search for an alternate file, so report file not found
  694. return SetResult( VideoResult::VIDEO_FILE_NOT_FOUND );
  695. }
  696. }
  697. // Ok, we didn't find the file and a system that could handle it
  698. // but hey, we are allowed to look for an alternate video file and system
  699. search_for_video:
  700. // start with the passed in filespec, and change the extension to wildcard
  701. char SearchFileSpec[MAX_PATH];
  702. V_strncpy( SearchFileSpec, pFileName, sizeof(SearchFileSpec) );
  703. V_SetExtension( SearchFileSpec, ".*", sizeof(SearchFileSpec) );
  704. FileFindHandle_t searchHandle = 0;
  705. const char *pMatchingFile = g_pFullFileSystem->FindFirstEx( SearchFileSpec, pPathID, &searchHandle );
  706. while ( pMatchingFile != nullptr )
  707. {
  708. const char *pExt = GetFileExtension( pMatchingFile );
  709. if ( pExt != nullptr )
  710. {
  711. // compare file extensions
  712. for ( int i = 0; i < m_ExtInfo.Count(); i++ )
  713. {
  714. // do we match a known extension?
  715. if ( stricmp( pExt, m_ExtInfo[i].m_FileExtension ) == STRINGS_MATCH )
  716. {
  717. // do we support the requested feature?
  718. if ( BITFLAGS_SET( m_ExtInfo[i].m_VideoFeatures, requiredFeature ) )
  719. {
  720. // Make sure it's a valid system
  721. sysIdx = GetIndexForSystem( m_ExtInfo[i].m_VideoSubSystem );
  722. if ( sysIdx != SYSTEM_NOT_FOUND )
  723. {
  724. // Start with any optional path we got...
  725. V_ExtractFilePath( pFileName, ActualFilePath, sizeof( ActualFilePath ) );
  726. // Append the search match file
  727. V_strncat( ActualFilePath, pMatchingFile, sizeof( ActualFilePath ) );
  728. if ( V_IsAbsolutePath( ActualFilePath ) )
  729. {
  730. V_strncpy( pResolvedFileName, ActualFilePath, resolvedFileNameMaxLen );
  731. }
  732. else
  733. {
  734. g_pFullFileSystem->RelativePathToFullPath( ActualFilePath, pPathID, pResolvedFileName, resolvedFileNameMaxLen );
  735. }
  736. // Return the system
  737. *pResolvedVideoSystem = GetSystemForIndex( sysIdx );
  738. g_pFullFileSystem->FindClose( searchHandle );
  739. return SetResult( VideoResult::SUCCESS );
  740. }
  741. }
  742. }
  743. }
  744. }
  745. // not usable.. keep searching
  746. pMatchingFile = g_pFullFileSystem->FindNext( searchHandle );
  747. }
  748. // we didn't find anything we could use
  749. g_pFullFileSystem->FindClose( searchHandle );
  750. return SetResult( VideoResult::VIDEO_FILE_NOT_FOUND );
  751. }
  752. VideoSystem_t CValveVideoServices::LocateSystemAndFeaturesForFileName( const char *pFileName, VideoSystemFeature_t *pFeatures, VideoSystemFeature_t requiredFeatures )
  753. {
  754. if ( pFeatures != nullptr)
  755. {
  756. *pFeatures = VideoSystemFeature::NO_FEATURES;
  757. }
  758. AssertExitV( IS_NOT_EMPTY( pFileName ), VideoSystem::NONE );
  759. if ( m_ExtInfo.Count() < 1 )
  760. {
  761. return VideoSystem::NONE;
  762. }
  763. // extract the file extension
  764. char fileExt[MAX_PATH];
  765. const char *pExt = GetFileExtension( pFileName );
  766. if ( pExt == nullptr )
  767. {
  768. return VideoSystem::NONE;
  769. }
  770. // lowercase it so we can compare
  771. V_strncpy( fileExt, pExt, sizeof(fileExt) );
  772. V_strlower( fileExt );
  773. for ( int i = 0; i < m_ExtInfo.Count(); i++ )
  774. {
  775. if ( V_stricmp( fileExt, m_ExtInfo[i].m_FileExtension ) == STRINGS_MATCH )
  776. {
  777. // must it have certain feature support?
  778. if ( requiredFeatures != VideoSystemFeature::NO_FEATURES )
  779. {
  780. if ( !BITFLAGS_SET( m_ExtInfo[i].m_VideoFeatures, requiredFeatures ) )
  781. {
  782. continue;
  783. }
  784. }
  785. if ( pFeatures != nullptr)
  786. {
  787. *pFeatures = m_ExtInfo[i].m_VideoFeatures;
  788. }
  789. return m_ExtInfo[i].m_VideoSubSystem;
  790. }
  791. }
  792. return VideoSystem::NONE;
  793. }
  794. bool CValveVideoServices::IsMatchAnyExtension( const char *pFileName )
  795. {
  796. if ( IS_EMPTY_STR( pFileName ) )
  797. {
  798. return false;
  799. }
  800. const char* pExt = GetFileExtension( pFileName );
  801. if ( pExt == nullptr )
  802. {
  803. return false;
  804. }
  805. return ( V_stricmp( pExt, FILE_EXTENSION_ANY_MATCHING_VIDEO ) == STRINGS_MATCH );
  806. }
  807. const char *CValveVideoServices::GetFileExtension( const char *pFileName )
  808. {
  809. if ( pFileName == nullptr )
  810. {
  811. return nullptr;
  812. }
  813. const char *pExt = V_GetFileExtension( pFileName );
  814. if ( pExt == nullptr )
  815. {
  816. return nullptr;
  817. }
  818. if ( pExt != pFileName && *( pExt - 1 ) == '.' )
  819. {
  820. pExt--;
  821. }
  822. return pExt;
  823. }
  824. // ===========================================================================
  825. // CVideoCommonServices - services used by any/multiple videoSubsystems
  826. // Functions are put here to avoid duplication and ensure they stay
  827. // consistant across all installed subsystems
  828. // ===========================================================================
  829. #ifdef WIN32
  830. typedef SHORT (WINAPI *GetAsyncKeyStateFn_t)( int vKey );
  831. static HINSTANCE s_UserDLLhInst = nullptr;
  832. GetAsyncKeyStateFn_t s_pfnGetAsyncKeyState = nullptr;
  833. #endif
  834. CVideoCommonServices::CVideoCommonServices()
  835. {
  836. ResetInputHandlerState();
  837. }
  838. CVideoCommonServices::~CVideoCommonServices()
  839. {
  840. if ( m_bInputHandlerInitialized )
  841. {
  842. TerminateFullScreenPlaybackInputHandler();
  843. }
  844. }
  845. void CVideoCommonServices::ResetInputHandlerState()
  846. {
  847. m_bInputHandlerInitialized = false;
  848. m_bScanAll = false;
  849. m_bScanEsc = false;
  850. m_bScanReturn = false;
  851. m_bScanSpace = false;
  852. m_bPauseEnabled = false;
  853. m_bAbortEnabled = false;
  854. m_bEscLast = false;
  855. m_bReturnLast = false;
  856. m_bSpaceLast = false;
  857. m_bForceMinPlayTime = false;
  858. m_bWindowed = false;
  859. m_playbackFlags = VideoPlaybackFlags::NO_PLAYBACK_OPTIONS;
  860. m_forcedMinTime = 0.0f;
  861. m_StartTime = 0;
  862. #ifdef WIN32
  863. s_UserDLLhInst = nullptr;
  864. s_pfnGetAsyncKeyState = nullptr;
  865. #endif
  866. }
  867. // ===========================================================================
  868. // Calculate the proper dimensions to play a video in full screen mode
  869. // uses the playback flags to supply rules for streaching, scaling and
  870. // centering the video
  871. // ===========================================================================
  872. bool CVideoCommonServices::CalculateVideoDimensions( int videoWidth, int videoHeight, int displayWidth, int displayHeight, VideoPlaybackFlags_t playbackFlags,
  873. int *pOutputWidth, int *pOutputHeight, int *pXOffset, int *pYOffset )
  874. {
  875. AssertExitF( pOutputWidth != nullptr && pOutputHeight != nullptr && pXOffset != nullptr && pYOffset != nullptr );
  876. AssertExitF( videoWidth >= 16 && videoHeight >= 16 && displayWidth > 64 && displayHeight > 64 );
  877. // extract relevant options
  878. bool bFillWindow = BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::FILL_WINDOW );
  879. bool bLockAspect = BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::LOCK_ASPECT_RATIO );
  880. bool bIntegralScale = BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::INTEGRAL_SCALE );
  881. bool bCenterVideo = BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::CENTER_VIDEO_IN_WINDOW );
  882. int curWidth = videoWidth;
  883. int curHeight = videoHeight;
  884. // Try and just play it actual size?
  885. if ( !bFillWindow )
  886. {
  887. // is the window the same size or larger?
  888. if ( curWidth <= displayWidth && curHeight <= displayHeight )
  889. {
  890. goto finish;
  891. }
  892. else // we need to shrink the video output
  893. {
  894. // if we aren't locking the aspect ratio, just shrink each axis until it fits
  895. if ( !bLockAspect )
  896. {
  897. while ( curWidth > displayWidth)
  898. {
  899. curWidth = ( bIntegralScale ) ? curWidth >> 1 : displayWidth;
  900. }
  901. while ( curHeight > displayHeight )
  902. {
  903. curHeight = ( bIntegralScale ) ? curHeight >> 1 : displayHeight;
  904. }
  905. goto finish;
  906. }
  907. else // we are locking the aspect ratio, and need to shrink the video
  908. {
  909. // integral scale only....
  910. if ( bIntegralScale )
  911. {
  912. while ( curWidth > displayWidth || curHeight > displayHeight)
  913. {
  914. curWidth >>= 1;
  915. curHeight >>= 1;
  916. }
  917. goto finish;
  918. }
  919. else // can scale variably..
  920. {
  921. float Xfactor = ( displayWidth / curWidth );
  922. float Yfactor = ( displayHeight / curHeight );
  923. float scale = MIN( Xfactor, Yfactor );
  924. curWidth = (int) ( curWidth * scale + 0.35f );
  925. curHeight = (int) ( curHeight * scale + 0.35f );
  926. clamp( curWidth, 0, displayWidth );
  927. clamp( curHeight, 0, displayHeight );
  928. goto finish;
  929. }
  930. }
  931. }
  932. }
  933. // ok.. we are wanting to fill the window....
  934. if ( bFillWindow )
  935. {
  936. // are we locking the aspect ratio?
  937. if ( bLockAspect )
  938. {
  939. // are we only allowed to scale integrally?
  940. if ( bIntegralScale )
  941. {
  942. while ( (curWidth << 1) <= displayWidth && (curHeight << 1) <= displayHeight )
  943. {
  944. curWidth <<= 1;
  945. curHeight <<= 1;
  946. }
  947. goto finish;
  948. }
  949. else
  950. {
  951. float Xfactor = ( (float)displayWidth / curWidth );
  952. float Yfactor = ( (float)displayHeight / curHeight );
  953. float scale = MIN( Xfactor, Yfactor );
  954. curWidth = (int) ( curWidth * scale + 0.35f );
  955. curHeight = (int) ( curHeight * scale + 0.35f );
  956. clamp( curWidth, 0, displayWidth );
  957. clamp( curHeight, 0, displayHeight );
  958. goto finish;
  959. }
  960. }
  961. else // we are not locking the aspect ratio...
  962. {
  963. if ( bIntegralScale )
  964. {
  965. while ( (curWidth << 1) <= displayWidth )
  966. {
  967. curWidth <<= 1;
  968. }
  969. while ( (curHeight << 1) <= displayHeight )
  970. {
  971. curHeight <<= 1;
  972. }
  973. goto finish;
  974. }
  975. else
  976. {
  977. curWidth = displayWidth;
  978. curHeight = displayHeight;
  979. goto finish;
  980. }
  981. }
  982. }
  983. finish:
  984. AssertExitF( displayWidth >= curWidth && displayHeight >= curHeight );
  985. if ( bCenterVideo )
  986. {
  987. *pXOffset = ( displayWidth - curWidth ) >> 1;
  988. *pYOffset = ( displayHeight - curHeight ) >> 1;
  989. }
  990. else
  991. {
  992. *pXOffset = 0;
  993. *pYOffset = 0;
  994. }
  995. *pOutputWidth = curWidth;
  996. *pOutputHeight = curHeight;
  997. return true;
  998. }
  999. float CVideoCommonServices::GetSystemVolume()
  1000. {
  1001. ConVarRef volumeConVar( "volume" );
  1002. float sysVolume = volumeConVar.IsValid() ? volumeConVar.GetFloat() : 1.0f;
  1003. clamp( sysVolume, 0.0f, 1.0f);
  1004. return sysVolume;
  1005. }
  1006. // ===========================================================================
  1007. // Sets up the state machine to receive messages and poll the keyboard
  1008. // while a full-screen video is playing
  1009. // ===========================================================================
  1010. VideoResult_t CVideoCommonServices::InitFullScreenPlaybackInputHandler( VideoPlaybackFlags_t playbackFlags, float forcedMinTime, bool windowed )
  1011. {
  1012. // already initialized?
  1013. if ( m_bInputHandlerInitialized )
  1014. {
  1015. WarningAssert( "called twice" );
  1016. return VideoResult::OPERATION_ALREADY_PERFORMED;
  1017. }
  1018. #ifdef WIN32
  1019. // 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
  1020. HINSTANCE m_UserDLLhInst = LoadLibrary( "user32.dll" );
  1021. if ( m_UserDLLhInst == NULL )
  1022. {
  1023. return VideoResult::SYSTEM_ERROR_OCCURED;
  1024. }
  1025. s_pfnGetAsyncKeyState = (GetAsyncKeyStateFn_t) GetProcAddress( m_UserDLLhInst, "GetAsyncKeyState" );
  1026. if ( s_pfnGetAsyncKeyState == NULL )
  1027. {
  1028. FreeLibrary( m_UserDLLhInst );
  1029. return VideoResult::SYSTEM_ERROR_OCCURED;
  1030. }
  1031. #endif
  1032. // save off playback options
  1033. m_playbackFlags = playbackFlags;
  1034. m_forcedMinTime = forcedMinTime;
  1035. m_bWindowed = windowed;
  1036. // process the pause and abort options
  1037. m_bScanAll = ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::PAUSE_ON_ANY_KEY | VideoPlaybackFlags::ABORT_ON_ANY_KEY );
  1038. m_bScanEsc = m_bScanAll || ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::PAUSE_ON_ESC | VideoPlaybackFlags::ABORT_ON_ESC );
  1039. m_bScanReturn = m_bScanAll || ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::PAUSE_ON_RETURN | VideoPlaybackFlags::ABORT_ON_RETURN );
  1040. m_bScanSpace = m_bScanAll || ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::PAUSE_ON_SPACE | VideoPlaybackFlags::ABORT_ON_SPACE );
  1041. m_bPauseEnabled = ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::PAUSE_ON_ESC | VideoPlaybackFlags::PAUSE_ON_RETURN | VideoPlaybackFlags::PAUSE_ON_SPACE | VideoPlaybackFlags::PAUSE_ON_ANY_KEY );
  1042. m_bAbortEnabled = ANY_BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::ABORT_ON_ESC | VideoPlaybackFlags::ABORT_ON_RETURN | VideoPlaybackFlags::ABORT_ON_SPACE | VideoPlaybackFlags::ABORT_ON_ANY_KEY );
  1043. // Setup the scan options
  1044. m_bEscLast = false;
  1045. m_bReturnLast = false;
  1046. m_bSpaceLast = false;
  1047. // Other Movie playback state init
  1048. m_bForceMinPlayTime = BITFLAGS_SET( playbackFlags, VideoPlaybackFlags::FORCE_MIN_PLAY_TIME ) && ( forcedMinTime > 0.0f );
  1049. // Note the start time
  1050. m_StartTime = Plat_FloatTime();
  1051. // and we're on
  1052. m_bInputHandlerInitialized = true;
  1053. return VideoResult::SUCCESS;
  1054. }
  1055. // ===========================================================================
  1056. // Pumps the message loops and checks for a supported event
  1057. // returns true if there is an event to check
  1058. // ===========================================================================
  1059. bool CVideoCommonServices::ProcessFullScreenInput( bool &bAbortEvent, bool &bPauseEvent, bool &bQuitEvent )
  1060. {
  1061. bAbortEvent = false;
  1062. bPauseEvent = false;
  1063. bQuitEvent = false;
  1064. if ( !m_bInputHandlerInitialized )
  1065. {
  1066. WarningAssert( "Not Initialized to call" );
  1067. return false;
  1068. }
  1069. // Pump OS Messages
  1070. #if defined( WIN32 )
  1071. MSG msg;
  1072. while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
  1073. {
  1074. // did we get a quit message?
  1075. if ( msg.message == WM_QUIT )
  1076. {
  1077. ::PostQuitMessage( msg.wParam );
  1078. return true;
  1079. }
  1080. // todo - look for alt-tab events, etc?
  1081. TranslateMessage( &msg );
  1082. DispatchMessage( &msg );
  1083. }
  1084. // Escape, return, or space stops or pauses the playback
  1085. bool bEscPressed = ( m_bScanEsc ) ? ( s_pfnGetAsyncKeyState( VK_ESCAPE ) & 0x8000 ) != 0 : false;
  1086. bool bReturnPressed = ( m_bScanReturn ) ? ( s_pfnGetAsyncKeyState( VK_RETURN ) & 0x8000 ) != 0 : false;
  1087. bool bSpacePressed = ( m_bScanSpace ) ? ( s_pfnGetAsyncKeyState( VK_SPACE ) & 0x8000 ) != 0 : false;
  1088. #elif defined(OSX)
  1089. g_pLauncherMgr->PumpWindowsMessageLoop();
  1090. // Escape, return, or space stops or pauses the playback
  1091. bool bEscPressed = ( m_bScanEsc ) ? CGEventSourceKeyState( kCGEventSourceStateCombinedSessionState, kVK_Escape ) : false;
  1092. bool bReturnPressed = ( m_bScanReturn ) ? CGEventSourceKeyState( kCGEventSourceStateCombinedSessionState, kVK_Return ) : false;
  1093. bool bSpacePressed = ( m_bScanSpace ) ? CGEventSourceKeyState( kCGEventSourceStateCombinedSessionState, kVK_Space ) : false;
  1094. #elif defined(LINUX)
  1095. g_pLauncherMgr->PumpWindowsMessageLoop();
  1096. // Escape, return, or space stops or pauses the playback
  1097. bool bEscPressed = false;
  1098. bool bReturnPressed = false;
  1099. bool bSpacePressed = false;
  1100. g_pLauncherMgr->PeekAndRemoveKeyboardEvents( &bEscPressed, &bReturnPressed, &bSpacePressed );
  1101. #endif
  1102. // Manual debounce of the keys, only interested in unpressed->pressed transitions
  1103. bool bEscEvent = ( bEscPressed != m_bEscLast ) && bEscPressed;
  1104. bool bReturnEvent = ( bReturnPressed != m_bReturnLast ) && bReturnPressed;
  1105. bool bSpaceEvent = ( bSpacePressed != m_bSpaceLast ) && bSpacePressed;
  1106. bool bAnyKeyEvent = bEscEvent || bReturnEvent || bSpaceEvent;
  1107. m_bEscLast = bEscPressed;
  1108. m_bReturnLast = bReturnPressed;
  1109. m_bSpaceLast = bSpacePressed;
  1110. // Are we forcing a minimum playback time?
  1111. // if so, no Abort or Pause events until the necessary time has elasped
  1112. if ( m_bForceMinPlayTime )
  1113. {
  1114. double elapsedTime = Plat_FloatTime() - m_StartTime;
  1115. if ( (float) elapsedTime > m_forcedMinTime )
  1116. {
  1117. m_bForceMinPlayTime = false; // turn off forced minimum
  1118. }
  1119. }
  1120. // any key events to check? ( provided minimum enforced playback has occurred )
  1121. if ( m_bForceMinPlayTime == false && bAnyKeyEvent )
  1122. {
  1123. // check for aborting the movie
  1124. if ( m_bAbortEnabled )
  1125. {
  1126. bAbortEvent = ( bAnyKeyEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::ABORT_ON_ANY_KEY ) ) ||
  1127. ( bEscEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::ABORT_ON_ESC ) ) ||
  1128. ( bReturnEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::ABORT_ON_RETURN ) ) ||
  1129. ( bSpaceEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::ABORT_ON_SPACE ) );
  1130. }
  1131. // check for pausing the movie?
  1132. if ( m_bPauseEnabled )
  1133. {
  1134. bPauseEvent = ( bAnyKeyEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::PAUSE_ON_ANY_KEY ) ) ||
  1135. ( bEscEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::PAUSE_ON_ESC ) ) ||
  1136. ( bReturnEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::PAUSE_ON_RETURN ) ) ||
  1137. ( bSpaceEvent && BITFLAGS_SET( m_playbackFlags, VideoPlaybackFlags::PAUSE_ON_SPACE ) );
  1138. }
  1139. }
  1140. // notify if any events triggered
  1141. return ( bAbortEvent || bPauseEvent );
  1142. }
  1143. VideoResult_t CVideoCommonServices::TerminateFullScreenPlaybackInputHandler()
  1144. {
  1145. if ( !m_bInputHandlerInitialized )
  1146. {
  1147. WarningAssert( "Not Initialized to call" );
  1148. return VideoResult::OPERATION_OUT_OF_SEQUENCE;
  1149. }
  1150. #if defined ( WIN32 )
  1151. FreeLibrary( s_UserDLLhInst ); // and free the dll we needed
  1152. #endif
  1153. ResetInputHandlerState();
  1154. return VideoResult::SUCCESS;
  1155. }