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
1464 lines
44 KiB
//========= 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; |
|
|
|
}
|
|
|