wscript: add videoservices

This commit is contained in:
nillerusr
2022-10-13 17:47:27 +03:00
parent bca0ae8c59
commit 2f15ebbfb8
20 changed files with 7 additions and 5 deletions

View File

@@ -0,0 +1,100 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// File: quicktime_common.h
//
// QuickTime limits and constants shared among all QuickTime functions
//
//=============================================================================
#ifndef QUICKTIME_COMMON_H
#define QUICKTIME_COMMON_H
#ifdef _WIN32
#pragma once
#endif
#ifdef OSX
// The OSX 10.7 SDK dropped support for the functions below, so we manually pull them in
#include <dlfcn.h>
typedef PixMapHandle
(*PFNGetGWorldPixMap)(GWorldPtr offscreenGWorld);
typedef Ptr
(*PFNGetPixBaseAddr)(PixMapHandle pm);
typedef Boolean
(*PFNLockPixels)(PixMapHandle pm);
typedef void
(*PFNUnlockPixels)(PixMapHandle pm);
typedef void
(*PFNDisposeGWorld)(GWorldPtr offscreenGWorld);
typedef void
(*PFNSetGWorld)(CGrafPtr port,GDHandle gdh);
typedef SInt32
(*PFNGetPixRowBytes)(PixMapHandle pm);
extern PFNGetGWorldPixMap GetGWorldPixMap;
extern PFNGetPixBaseAddr GetPixBaseAddr;
extern PFNLockPixels LockPixels;
extern PFNUnlockPixels UnlockPixels;
extern PFNDisposeGWorld DisposeGWorld;
extern PFNSetGWorld SetGWorld;
extern PFNGetPixRowBytes GetPixRowBytes;
#endif
// constant that define the bounds of various inputs
static const int cMinVideoFrameWidth = 16;
static const int cMinVideoFrameHeight = 16;
static const int cMaxVideoFrameWidth = 2 * 2048;
static const int cMaxVideoFrameHeight = 2 * 2048;
static const int cMinFPS = 1;
static const int cMaxFPS = 600;
static const float cMinDuration = 0.016666666f; // 1/60th second
static const float cMaxDuration = 3600.0f; // 1 Hour
static const int cMinSampleRate = 11025; // 1/4 CD sample rate
static const int cMaxSampleRate = 88200; // 2x CD rate
#define NO_MORE_INTERESTING_TIMES -2
#define END_OF_QUICKTIME_MOVIE -1
// ===========================================================================
// Macros & Utility functions
// ===========================================================================
#define SAFE_DISPOSE_HANDLE( _handle ) if ( _handle != nullptr ) { DisposeHandle( (Handle) _handle ); _handle = nullptr; }
#define SAFE_DISPOSE_GWORLD( _gworld ) if ( _gworld != nullptr ) { DisposeGWorld( _gworld ); _gworld = nullptr; }
#define SAFE_DISPOSE_MOVIE( _movie ) if ( _movie != nullptr ) { DisposeMovie( _movie ); ThreadSleep(10); Assert( GetMoviesError() == noErr ); _movie = nullptr; }
#define SAFE_RELEASE_AUDIOCONTEXT( _cxt ) if ( _cxt != nullptr ) { QTAudioContextRelease( _cxt ); _cxt = nullptr; }
#define SAFE_RELEASE_CFREF( _ref ) if ( _ref != nullptr ) { CFRelease( _ref ); _ref = nullptr; }
// Utility functions
extern char *COPY_STRING( const char *pString );
bool MovieGetStaticFrameRate( Movie inMovie, VideoFrameRate_t &theFrameRate );
bool SetGWorldDecodeGamma( CGrafPtr theGWorld, VideoPlaybackGamma_t gamma );
bool CreateMovieAudioContext( bool enableAudio, Movie inMovie, QTAudioContextRef *pAudioConectext, bool setVolume = false, float *pCurrentVolume = nullptr );
VideoPlaybackGamma_t GetSystemPlaybackGamma();
//-----------------------------------------------------------------------------
// Computes a power of two at least as big as the passed-in number
//-----------------------------------------------------------------------------
static inline int ComputeGreaterPowerOfTwo( int n )
{
int i = 1;
while ( i < n )
{
i <<= 1;
}
return i;
}
#endif // QUICKTIME_COMMON_H

View File

@@ -0,0 +1,962 @@
//========= 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 "vtf/vtf.h"
#include "pixelwriter.h"
#include "tier3/tier3.h"
#include "platform.h"
#include "quicktime_material.h"
#if defined ( WIN32 )
#include <WinDef.h>
#include <../dx9sdk/include/dsound.h>
#endif
#include "tier0/memdbgon.h"
// ===========================================================================
// CQuicktimeMaterialRGBTextureRegenerator - Inherited from ITextureRegenerator
// Copies and converts the buffer bits to texture bits
// Currently only supports 32-bit BGRA
// ===========================================================================
CQuicktimeMaterialRGBTextureRegenerator::CQuicktimeMaterialRGBTextureRegenerator() :
m_SrcGWorld( nullptr ),
m_nSourceWidth( 0 ),
m_nSourceHeight( 0 )
{
}
CQuicktimeMaterialRGBTextureRegenerator::~CQuicktimeMaterialRGBTextureRegenerator()
{
// nothing to do
}
void CQuicktimeMaterialRGBTextureRegenerator::SetSourceGWorld( GWorldPtr theGWorld, int nWidth, int nHeight )
{
m_SrcGWorld = theGWorld;
m_nSourceWidth = nWidth;
m_nSourceHeight = nHeight;
}
void CQuicktimeMaterialRGBTextureRegenerator::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
{
AssertExit( pVTFTexture != nullptr );
// Error condition, should only have 1 frame, 1 face, 1 mip level
if ( ( pVTFTexture->FrameCount() > 1 ) || ( pVTFTexture->FaceCount() > 1 ) || ( pVTFTexture->MipCount() > 1 ) || ( pVTFTexture->Depth() > 1 ) )
{
WarningAssert( "Texture Properties Incorrect ");
memset( pVTFTexture->ImageData(), 0xAA, pVTFTexture->ComputeTotalSize() );
return;
}
// Make sure we have a valid video image source
if ( m_SrcGWorld == nullptr )
{
WarningAssert( "Video texture source not set" );
memset( pVTFTexture->ImageData(), 0xCC, pVTFTexture->ComputeTotalSize() );
return;
}
// Verify the destination texture is set up correctly
Assert( pVTFTexture->Format() == IMAGE_FORMAT_BGRA8888 );
Assert( pVTFTexture->RowSizeInBytes( 0 ) >= pVTFTexture->Width() * 4 );
Assert( pVTFTexture->Width() >= m_nSourceWidth );
Assert( pVTFTexture->Height() >= m_nSourceHeight );
// Copy directly from the Quicktime GWorld
PixMapHandle thePixMap = GetGWorldPixMap( m_SrcGWorld );
if ( LockPixels( thePixMap ) )
{
BYTE *pImageData = pVTFTexture->ImageData();
int dstStride = pVTFTexture->RowSizeInBytes( 0 );
BYTE *pSrcData = (BYTE*) GetPixBaseAddr( thePixMap );
long srcStride = QTGetPixMapHandleRowBytes( thePixMap );
int rowSize = m_nSourceWidth * 4;
for (int y = 0; y < m_nSourceHeight; y++ )
{
memcpy( pImageData, pSrcData, rowSize );
pImageData+= dstStride;
pSrcData+= srcStride;
}
UnlockPixels( thePixMap );
}
else
{
WarningAssert( "LockPixels Failed" );
}
}
void CQuicktimeMaterialRGBTextureRegenerator::Release()
{
// we don't invoke the destructor here, we're not using the no-release extensions
}
// ===========================================================================
// CQuickTimeMaterial class - creates a material, opens a QuickTime movie
// and plays the movie onto the material
// ===========================================================================
//-----------------------------------------------------------------------------
// CQuickTimeMaterial Constructor
//-----------------------------------------------------------------------------
CQuickTimeMaterial::CQuickTimeMaterial() :
m_pFileName( nullptr ),
m_MovieGWorld( nullptr ),
m_QTMovie( nullptr ),
m_AudioContext( nullptr ),
m_bInitCalled( false )
{
Reset();
}
//-----------------------------------------------------------------------------
// CQuickTimeMaterial Destructor
//-----------------------------------------------------------------------------
CQuickTimeMaterial::~CQuickTimeMaterial()
{
Reset();
}
void CQuickTimeMaterial::Reset()
{
SetQTFileName( nullptr );
DestroyProceduralTexture();
DestroyProceduralMaterial();
m_TexCordU = 0.0f;
m_TexCordV = 0.0f;
m_VideoFrameWidth = 0;
m_VideoFrameHeight = 0;
m_PlaybackFlags = VideoPlaybackFlags::NO_PLAYBACK_OPTIONS;
m_bMovieInitialized = false;
m_bMoviePlaying = false;
m_bMovieFinishedPlaying = false;
m_bMoviePaused = false;
m_bLoopMovie = false;
m_bHasAudio = false;
m_bMuted = false;
m_CurrentVolume = 0.0f;
m_QTMovieTimeScale = 0;
m_QTMovieDuration = 0;
m_QTMovieDurationinSec = 0.0f;
m_QTMovieFrameRate.SetFPS( 0, false );
SAFE_RELEASE_AUDIOCONTEXT( m_AudioContext );
SAFE_DISPOSE_GWORLD( m_MovieGWorld );
SAFE_DISPOSE_MOVIE( m_QTMovie );
m_LastResult = VideoResult::SUCCESS;
}
void CQuickTimeMaterial::SetQTFileName( const char *theQTMovieFileName )
{
SAFE_DELETE_ARRAY( m_pFileName );
if ( theQTMovieFileName != nullptr )
{
AssertMsg( V_strlen( theQTMovieFileName ) <= MAX_QT_FILENAME_LEN, "Bad Quicktime Movie Filename" );
m_pFileName = COPY_STRING( theQTMovieFileName );
}
}
VideoResult_t CQuickTimeMaterial::SetResult( VideoResult_t status )
{
m_LastResult = status;
return status;
}
//-----------------------------------------------------------------------------
// Video information functions
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Returns the resolved filename of the video, as it might differ from
// what the user supplied, (also with absolute path)
//-----------------------------------------------------------------------------
const char *CQuickTimeMaterial::GetVideoFileName()
{
return m_pFileName;
}
VideoFrameRate_t &CQuickTimeMaterial::GetVideoFrameRate()
{
return m_QTMovieFrameRate;
}
VideoResult_t CQuickTimeMaterial::GetLastResult()
{
return m_LastResult;
}
//-----------------------------------------------------------------------------
// Audio Functions
//-----------------------------------------------------------------------------
bool CQuickTimeMaterial::HasAudio()
{
return m_bHasAudio;
}
bool CQuickTimeMaterial::SetVolume( float fVolume )
{
clamp( fVolume, 0.0f, 1.0f );
m_CurrentVolume = fVolume;
if ( m_AudioContext != nullptr && m_bHasAudio )
{
short movieVolume = (short) ( m_CurrentVolume * 256.0f );
SetMovieVolume( m_QTMovie, movieVolume );
SetResult( VideoResult::SUCCESS );
return true;
}
SetResult( VideoResult::AUDIO_ERROR_OCCURED );
return false;
}
float CQuickTimeMaterial::GetVolume()
{
return m_CurrentVolume;
}
void CQuickTimeMaterial::SetMuted( bool bMuteState )
{
AssertExitFunc( m_bMoviePlaying, SetResult( VideoResult::OPERATION_OUT_OF_SEQUENCE) );
SetResult( VideoResult::SUCCESS );
if ( bMuteState == m_bMuted ) // no change?
{
return;
}
m_bMuted = bMuteState;
if ( m_bHasAudio )
{
OSStatus result = SetMovieAudioMute( m_QTMovie, m_bMuted, 0 );
AssertExitFunc( result == noErr, SetResult( VideoResult::AUDIO_ERROR_OCCURED) );
}
SetResult( VideoResult::SUCCESS );
}
bool CQuickTimeMaterial::IsMuted()
{
return m_bMuted;
}
VideoResult_t CQuickTimeMaterial::SoundDeviceCommand( VideoSoundDeviceOperation_t operation, void *pDevice, void *pData )
{
AssertExitV( m_bMovieInitialized || m_bMoviePlaying, VideoResult::OPERATION_OUT_OF_SEQUENCE );
switch( operation )
{
// On win32, we try and create an audio context from a GUID
case VideoSoundDeviceOperation::SET_DIRECT_SOUND_DEVICE:
{
#if defined ( WIN32 )
SAFE_RELEASE_AUDIOCONTEXT( m_AudioContext );
return ( CreateMovieAudioContext( m_bHasAudio, m_QTMovie, &m_AudioContext ) ? SetResult( VideoResult::SUCCESS ) : SetResult( VideoResult::AUDIO_ERROR_OCCURED ) );
#else
// On any other OS, we don't support this operation
return SetResult( VideoResult::OPERATION_NOT_SUPPORTED );
#endif
}
case VideoSoundDeviceOperation::SET_SOUND_MANAGER_DEVICE:
{
#if defined ( OSX )
SAFE_RELEASE_AUDIOCONTEXT( m_AudioContext );
return ( CreateMovieAudioContext( m_bHasAudio, m_QTMovie, &m_AudioContext ) ? SetResult( VideoResult::SUCCESS ) : SetResult( VideoResult::AUDIO_ERROR_OCCURED ) );
#else
// On any other OS, we don't support this operation
return SetResult( VideoResult::OPERATION_NOT_SUPPORTED );
#endif
}
case VideoSoundDeviceOperation::SET_LIB_AUDIO_DEVICE:
case VideoSoundDeviceOperation::HOOK_X_AUDIO:
case VideoSoundDeviceOperation::SET_MILES_SOUND_DEVICE:
{
return SetResult( VideoResult::OPERATION_NOT_SUPPORTED );
}
default:
{
return SetResult( VideoResult::BAD_INPUT_PARAMETERS );
}
}
}
//-----------------------------------------------------------------------------
// Initializes the video material
//-----------------------------------------------------------------------------
bool CQuickTimeMaterial::Init( const char *pMaterialName, const char *pFileName, VideoPlaybackFlags_t flags )
{
SetResult( VideoResult::BAD_INPUT_PARAMETERS );
AssertExitF( IS_NOT_EMPTY( pFileName ) );
AssertExitF( m_bInitCalled == false );
m_PlaybackFlags = flags;
OpenQTMovie( pFileName ); // Open up the Quicktime file
if ( !m_bMovieInitialized )
{
return false; // Something bad happened when we went to open
}
// Now we can properly setup our regenerators
m_TextureRegen.SetSourceGWorld( m_MovieGWorld, m_VideoFrameWidth, m_VideoFrameHeight );
CreateProceduralTexture( pMaterialName );
CreateProceduralMaterial( pMaterialName );
// Start movie playback
if ( !BITFLAGS_SET( m_PlaybackFlags, VideoPlaybackFlags::DONT_AUTO_START_VIDEO ) )
{
StartVideo();
}
m_bInitCalled = true; // Look, if you only got one shot...
return true;
}
void CQuickTimeMaterial::Shutdown( void )
{
StopVideo();
Reset();
}
//-----------------------------------------------------------------------------
// Video playback state functions
//-----------------------------------------------------------------------------
bool CQuickTimeMaterial::IsVideoReadyToPlay()
{
return m_bMovieInitialized;
}
bool CQuickTimeMaterial::IsVideoPlaying()
{
return m_bMoviePlaying;
}
//-----------------------------------------------------------------------------
// Checks to see if the video has a new frame ready to be rendered and
// downloaded into the texture and eventually display
//-----------------------------------------------------------------------------
bool CQuickTimeMaterial::IsNewFrameReady( void )
{
// Are we waiting to start playing the first frame? if so, tell them we are ready!
if ( m_bMovieInitialized == true )
{
return true;
}
// We better be playing the movie
AssertExitF( m_bMoviePlaying );
// paused?
if ( m_bMoviePaused )
{
return false;
}
TimeValue curMovieTime = GetMovieTime( m_QTMovie, nullptr );
if ( curMovieTime >= m_QTMovieDuration || m_NextInterestingTimeToPlay == NO_MORE_INTERESTING_TIMES )
{
// if we are looping, we have another frame, otherwise no
return m_bLoopMovie;
}
// Enough time passed to get to next frame??
if ( curMovieTime < m_NextInterestingTimeToPlay )
{
// nope.. use the previous frame
return false;
}
// we have a new frame we want then..
return true;
}
bool CQuickTimeMaterial::IsFinishedPlaying()
{
return m_bMovieFinishedPlaying;
}
void CQuickTimeMaterial::SetLooping( bool bLoopVideo )
{
m_bLoopMovie = bLoopVideo;
}
bool CQuickTimeMaterial::IsLooping()
{
return m_bLoopMovie;
}
void CQuickTimeMaterial::SetPaused( bool bPauseState )
{
if ( !m_bMoviePlaying || m_bMoviePaused == bPauseState )
{
Assert( m_bMoviePlaying );
return;
}
if ( bPauseState ) // Pausing the movie?
{
// Save off current time and set paused state
m_MoviePauseTime = GetMovieTime( m_QTMovie, nullptr );
StopMovie( m_QTMovie );
}
else // unpausing the movie
{
// Reset the movie to the paused time
SetMovieTimeValue( m_QTMovie, m_MoviePauseTime );
StartMovie( m_QTMovie );
Assert( GetMoviesError() == noErr );
}
m_bMoviePaused = bPauseState;
}
bool CQuickTimeMaterial::IsPaused()
{
return ( m_bMoviePlaying ) ? m_bMoviePaused : false;
}
// Begins playback of the movie
bool CQuickTimeMaterial::StartVideo()
{
if ( !m_bMovieInitialized )
{
Assert( false );
SetResult( VideoResult::OPERATION_ALREADY_PERFORMED );
return false;
}
// Start the movie playing at the first frame
SetMovieTimeValue( m_QTMovie, m_MovieFirstFrameTime );
Assert( GetMoviesError() == noErr );
StartMovie( m_QTMovie );
Assert( GetMoviesError() == noErr );
// Transition to playing state
m_bMovieInitialized = false;
m_bMoviePlaying = true;
// Deliberately set the next interesting time to the current time to
// insure that the ::update() call causes the textures to be downloaded
m_NextInterestingTimeToPlay = m_MovieFirstFrameTime;
Update();
return true;
}
// stops movie for good, frees resources, but retains texture & material of last frame rendered
bool CQuickTimeMaterial::StopVideo()
{
if ( !m_bMoviePlaying )
{
SetResult( VideoResult::OPERATION_OUT_OF_SEQUENCE );
return false;
}
StopMovie( m_QTMovie );
m_bMoviePlaying = false;
m_bMoviePaused = false;
m_bMovieFinishedPlaying = true;
// free resources
CloseQTFile();
SetResult( VideoResult::SUCCESS );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Updates our scene
// Output : true = movie playing ok, false = time to end movie
// supposed to be: Returns true on a new frame of video being downloaded into the texture
//-----------------------------------------------------------------------------
bool CQuickTimeMaterial::Update( void )
{
AssertExitF( m_bMoviePlaying );
OSType qTypes[1] = { VisualMediaCharacteristic };
// are we paused? can't update if so...
if ( m_bMoviePaused )
{
return true; // reuse the last frame
}
// Get current time in the movie
TimeValue curMovieTime = GetMovieTime( m_QTMovie, nullptr );
// Did we hit the end of the movie?
if ( curMovieTime >= m_QTMovieDuration )
{
// If we're not looping, then report that we are done updating
if ( m_bLoopMovie == false )
{
StopVideo();
return false;
}
// Reset the movie to the start time
SetMovieTimeValue( m_QTMovie, m_MovieFirstFrameTime );
AssertExitF( GetMoviesError() == noErr );
// Assure fall through to render a new frame
m_NextInterestingTimeToPlay = m_MovieFirstFrameTime;
}
// Are we on the last frame of the movie? (but not past the end of any audio?)
if ( m_NextInterestingTimeToPlay == NO_MORE_INTERESTING_TIMES )
{
return true; // reuse last frame
}
// Enough time passed to get to next frame?
if ( curMovieTime < m_NextInterestingTimeToPlay )
{
// nope.. use the previous frame
return true;
}
// move the movie along
UpdateMovie( m_QTMovie );
AssertExitF( GetMoviesError() == noErr );
// Let QuickTime render the frame
MoviesTask( m_QTMovie, 0L );
AssertExitF( GetMoviesError() == noErr );
// Get the next frame after the current time (the movie may have advanced a bit during UpdateMovie() and MovieTasks()
GetMovieNextInterestingTime( m_QTMovie, nextTimeStep | nextTimeEdgeOK, 1, qTypes, GetMovieTime( m_QTMovie, nullptr ), fixed1, &m_NextInterestingTimeToPlay, nullptr );
// hit the end of the movie?
if ( GetMoviesError() == invalidTime || m_NextInterestingTimeToPlay == END_OF_QUICKTIME_MOVIE )
{
m_NextInterestingTimeToPlay = NO_MORE_INTERESTING_TIMES;
}
// Regenerate our texture, it'll grab from the GWorld Directly
m_Texture->Download();
SetResult( VideoResult::SUCCESS );
return true;
}
//-----------------------------------------------------------------------------
// Returns the material
//-----------------------------------------------------------------------------
IMaterial *CQuickTimeMaterial::GetMaterial()
{
return m_Material;
}
//-----------------------------------------------------------------------------
// Returns the texcoord range
//-----------------------------------------------------------------------------
void CQuickTimeMaterial::GetVideoTexCoordRange( float *pMaxU, float *pMaxV )
{
AssertExit( pMaxU != nullptr && pMaxV != nullptr );
if ( m_Texture == nullptr ) // no texture?
{
*pMaxU = *pMaxV = 1.0f;
return;
}
*pMaxU = m_TexCordU;
*pMaxV = m_TexCordV;
}
//-----------------------------------------------------------------------------
// Returns the frame size of the QuickTime Video in pixels
//-----------------------------------------------------------------------------
void CQuickTimeMaterial::GetVideoImageSize( int *pWidth, int *pHeight )
{
Assert( pWidth != nullptr && pHeight != nullptr );
*pWidth = m_VideoFrameWidth;
*pHeight = m_VideoFrameHeight;
}
float CQuickTimeMaterial::GetVideoDuration()
{
return m_QTMovieDurationinSec;
}
int CQuickTimeMaterial::GetFrameCount()
{
return m_QTMovieFrameCount;
}
//-----------------------------------------------------------------------------
// Sets the frame for an QuickTime Material (use instead of SetTime)
//-----------------------------------------------------------------------------
bool CQuickTimeMaterial::SetFrame( int FrameNum )
{
if ( !m_bMoviePlaying )
{
Assert( false );
SetResult( VideoResult::OPERATION_OUT_OF_SEQUENCE );
return false;
}
float theTime = (float) FrameNum * m_QTMovieFrameRate.GetFPS();
return SetTime( theTime );
}
int CQuickTimeMaterial::GetCurrentFrame()
{
AssertExitV( m_bMoviePlaying, -1 );
TimeValue curTime = m_bMoviePaused ? m_MoviePauseTime : GetMovieTime( m_QTMovie, nullptr );
return curTime / m_QTMovieFrameRate.GetUnitsPerFrame();
}
float CQuickTimeMaterial::GetCurrentVideoTime()
{
AssertExitV( m_bMoviePlaying, -1.0f );
TimeValue curTime = m_bMoviePaused ? m_MoviePauseTime : GetMovieTime( m_QTMovie, nullptr );
return curTime / m_QTMovieFrameRate.GetUnitsPerSecond();
}
bool CQuickTimeMaterial::SetTime( float flTime )
{
AssertExitF( m_bMoviePlaying );
AssertExitF( flTime >= 0 && flTime < m_QTMovieDurationinSec );
TimeValue newTime = (TimeValue) ( flTime * m_QTMovieFrameRate.GetUnitsPerSecond() + 0.5f) ;
clamp( newTime, m_MovieFirstFrameTime, m_QTMovieDuration );
// Are we paused?
if ( m_bMoviePaused )
{
m_MoviePauseTime = newTime;
return true;
}
TimeValue curMovieTime = GetMovieTime( m_QTMovie, nullptr );
// Don't stop and reset movie if we are within 1 frame of the requested time
if ( newTime <= curMovieTime - m_QTMovieFrameRate.GetUnitsPerFrame() || newTime >= curMovieTime + m_QTMovieFrameRate.GetUnitsPerFrame() )
{
// Reset the movie to the requested time
StopMovie( m_QTMovie );
SetMovieTimeValue( m_QTMovie, newTime );
StartMovie( m_QTMovie );
Assert( GetMoviesError() == noErr );
}
return true;
}
//-----------------------------------------------------------------------------
// Initializes, shuts down the procedural texture
//-----------------------------------------------------------------------------
void CQuickTimeMaterial::CreateProceduralTexture( const char *pTextureName )
{
AssertIncRange( m_VideoFrameWidth, cMinVideoFrameWidth, cMaxVideoFrameWidth );
AssertIncRange( m_VideoFrameHeight, cMinVideoFrameHeight, cMaxVideoFrameHeight );
AssertStr( pTextureName );
// Either make the texture the same dimensions as the video,
// or choose power-of-two textures which are at least as big as the video
bool actualSizeTexture = BITFLAGS_SET( m_PlaybackFlags, VideoPlaybackFlags::TEXTURES_ACTUAL_SIZE );
int nWidth = ( actualSizeTexture ) ? ALIGN_VALUE( m_VideoFrameWidth, TEXTURE_SIZE_ALIGNMENT ) : ComputeGreaterPowerOfTwo( m_VideoFrameWidth );
int nHeight = ( actualSizeTexture ) ? ALIGN_VALUE( m_VideoFrameHeight, TEXTURE_SIZE_ALIGNMENT ) : ComputeGreaterPowerOfTwo( m_VideoFrameHeight );
// initialize the procedural texture as 32-it RGBA, w/o mipmaps
m_Texture.InitProceduralTexture( pTextureName, "VideoCacheTextures", nWidth, nHeight,
IMAGE_FORMAT_BGRA8888, TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_NOMIP |
TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_NOLOD );
// Use this to get the updated frame from the remote connection
m_Texture->SetTextureRegenerator( &m_TextureRegen /* , false */ );
// compute the texcoords
int nTextureWidth = m_Texture->GetActualWidth();
int nTextureHeight = m_Texture->GetActualHeight();
m_TexCordU = ( nTextureWidth > 0 ) ? (float) m_VideoFrameWidth / (float) nTextureWidth : 0.0f;
m_TexCordV = ( nTextureHeight > 0 ) ? (float) m_VideoFrameHeight / (float) nTextureHeight : 0.0f;
}
void CQuickTimeMaterial::DestroyProceduralTexture()
{
if ( m_Texture != nullptr )
{
// DO NOT Call release on the Texture Regenerator, as it will destroy this object! bad bad bad
// instead we tell it to assign a NULL regenerator and flag it to not call release
m_Texture->SetTextureRegenerator( nullptr /*, false */ );
// Texture, texture go away...
m_Texture.Shutdown( true );
}
}
//-----------------------------------------------------------------------------
// Initializes, shuts down the procedural material
//-----------------------------------------------------------------------------
void CQuickTimeMaterial::CreateProceduralMaterial( const char *pMaterialName )
{
// create keyvalues if necessary
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
{
pVMTKeyValues->SetString( "$basetexture", m_Texture->GetName() );
pVMTKeyValues->SetInt( "$nobasetexture", 1 );
pVMTKeyValues->SetInt( "$nofog", 1 );
pVMTKeyValues->SetInt( "$spriteorientation", 3 );
pVMTKeyValues->SetInt( "$translucent", 1 );
pVMTKeyValues->SetInt( "$nolod", 1 );
pVMTKeyValues->SetInt( "$nomip", 1 );
pVMTKeyValues->SetInt( "$gammacolorread", 0 );
}
// FIXME: gak, this is backwards. Why doesn't the material just see that it has a funky basetexture?
m_Material.Init( pMaterialName, pVMTKeyValues );
m_Material->Refresh();
}
void CQuickTimeMaterial::DestroyProceduralMaterial()
{
// Store the internal material pointer for later use
IMaterial *pMaterial = m_Material;
m_Material.Shutdown();
materials->UncacheUnusedMaterials();
// Now be sure to free that material because we don't want to reference it again later, we'll recreate it!
if ( pMaterial != nullptr )
{
pMaterial->DeleteIfUnreferenced();
}
}
//-----------------------------------------------------------------------------
// Opens a movie file using quicktime
//-----------------------------------------------------------------------------
void CQuickTimeMaterial::OpenQTMovie( const char *theQTMovieFileName )
{
AssertExit( IS_NOT_EMPTY( theQTMovieFileName ) );
// Set graphics port
#if defined ( WIN32 )
SetGWorld ( (CGrafPtr) GetNativeWindowPort( nil ), nil );
#elif defined ( OSX )
SetGWorld( nil, nil );
#endif
SetQTFileName( theQTMovieFileName );
Handle MovieFileDataRef = nullptr;
OSType MovieFileDataRefType = 0;
CFStringRef imageStrRef = CFStringCreateWithCString ( NULL, theQTMovieFileName, 0 );
AssertExitFunc( imageStrRef != nullptr, SetResult( VideoResult::SYSTEM_ERROR_OCCURED ) );
OSErr status = QTNewDataReferenceFromFullPathCFString( imageStrRef, (QTPathStyle) kQTNativeDefaultPathStyle, 0, &MovieFileDataRef, &MovieFileDataRefType );
AssertExitFunc( status == noErr, SetResult( VideoResult::FILE_ERROR_OCCURED ) );
CFRelease( imageStrRef );
status = NewMovieFromDataRef( &m_QTMovie, newMovieActive, nil, MovieFileDataRef, MovieFileDataRefType );
SAFE_DISPOSE_HANDLE( MovieFileDataRef );
if ( status != noErr )
{
Assert( false );
Reset();
SetResult( VideoResult::VIDEO_ERROR_OCCURED );
return;
}
// disabling audio?
if ( BITFLAGS_SET( m_PlaybackFlags, VideoPlaybackFlags::NO_AUDIO ) )
{
m_bHasAudio = false;
}
else
{
// does movie have audio?
Track audioTrack = GetMovieIndTrackType( m_QTMovie, 1, SoundMediaType, movieTrackMediaType );
m_bHasAudio = ( audioTrack != nullptr );
}
// Now we need to extract the time info from the QT Movie
m_QTMovieTimeScale = GetMovieTimeScale( m_QTMovie );
m_QTMovieDuration = GetMovieDuration( m_QTMovie );
// compute movie duration
m_QTMovieDurationinSec = float ( double( m_QTMovieDuration ) / double( m_QTMovieTimeScale ) );
if ( !MovieGetStaticFrameRate( m_QTMovie, m_QTMovieFrameRate ) )
{
WarningAssert( "Couldn't Get Frame Rate" );
}
// and get an estimated frame count
m_QTMovieFrameCount = m_QTMovieDuration / m_QTMovieTimeScale;
if ( m_QTMovieFrameRate.GetUnitsPerSecond() == m_QTMovieTimeScale )
{
m_QTMovieFrameCount = m_QTMovieDuration / m_QTMovieFrameRate.GetUnitsPerFrame();
}
else
{
m_QTMovieFrameCount = (int) ( (float) m_QTMovieDurationinSec * m_QTMovieFrameRate.GetFPS() + 0.5f );
}
// what size do we set the output rect to?
GetMovieNaturalBoundsRect(m_QTMovie, &m_QTMovieRect);
m_VideoFrameWidth = m_QTMovieRect.right;
m_VideoFrameHeight = m_QTMovieRect.bottom;
// Sanity check...
AssertExitFunc( m_QTMovieRect.top == 0 && m_QTMovieRect.left == 0 &&
m_QTMovieRect.right >= cMinVideoFrameWidth && m_QTMovieRect.right <= cMaxVideoFrameWidth &&
m_QTMovieRect.bottom >= cMinVideoFrameHeight && m_QTMovieRect.bottom <= cMaxVideoFrameHeight &&
m_QTMovieRect.right % 4 == 0,
SetResult( VideoResult::VIDEO_ERROR_OCCURED ) );
// Setup the QuiuckTime Graphics World for the Movie
status = QTNewGWorld( &m_MovieGWorld, k32BGRAPixelFormat, &m_QTMovieRect, nil, nil, 0 );
AssertExit( status == noErr );
// Setup the playback gamma according to the convar
SetGWorldDecodeGamma( m_MovieGWorld, VideoPlaybackGamma::USE_GAMMA_CONVAR );
// Assign the GWorld to this movie
SetMovieGWorld( m_QTMovie, m_MovieGWorld, nil );
// Setup Movie Audio, unless suppressed
if ( !CreateMovieAudioContext( m_bHasAudio, m_QTMovie, &m_AudioContext, true, &m_CurrentVolume ) )
{
SetResult( VideoResult::AUDIO_ERROR_OCCURED );
WarningAssert( "Couldn't Set Audio" );
}
// Get the time of the first frame
OSType qTypes[1] = { VisualMediaCharacteristic };
short qFlags = nextTimeStep | nextTimeEdgeOK; // use nextTimeStep instead of nextTimeMediaSample for MPEG 1-2 compatibility
GetMovieNextInterestingTime( m_QTMovie, qFlags, 1, qTypes, (TimeValue) 0, fixed1, &m_MovieFirstFrameTime, NULL );
AssertExitFunc( GetMoviesError() == noErr, SetResult( VideoResult::VIDEO_ERROR_OCCURED ) );
// Preroll the movie
if ( BITFLAGS_SET( m_PlaybackFlags, VideoPlaybackFlags::PRELOAD_VIDEO ) )
{
Fixed playRate = GetMoviePreferredRate( m_QTMovie );
status = PrerollMovie( m_QTMovie, m_MovieFirstFrameTime, playRate );
AssertExitFunc( status == noErr, SetResult( VideoResult::VIDEO_ERROR_OCCURED ) );
}
m_bMovieInitialized = true;
}
void CQuickTimeMaterial::CloseQTFile()
{
if ( m_QTMovie == nullptr )
{
return;
}
SAFE_RELEASE_AUDIOCONTEXT( m_AudioContext );
SAFE_DISPOSE_GWORLD( m_MovieGWorld );
SAFE_DISPOSE_MOVIE( m_QTMovie );
SetQTFileName( nullptr );
}

View File

@@ -0,0 +1,221 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef QUICKTIME_MATERIAL_H
#define QUICKTIME_MATERIAL_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
class IFileSystem;
class IMaterialSystem;
class CQuickTimeMaterial;
//-----------------------------------------------------------------------------
// Global interfaces - you already did the needed includes, right?
//-----------------------------------------------------------------------------
extern IFileSystem *g_pFileSystem;
extern IMaterialSystem *materials;
//-----------------------------------------------------------------------------
// Quicktime includes
//-----------------------------------------------------------------------------
#if defined ( OSX )
#include <quicktime/QTML.h>
#include <quicktime/Movies.h>
#include <quicktime/MediaHandlers.h>
#elif defined ( WIN32 )
#include <QTML.h>
#include <Movies.h>
#include <windows.h>
#include <MediaHandlers.h>
#elif
#error "Quicktime not supported on this target platform"
#endif
#include "video/ivideoservices.h"
#include "video_macros.h"
#include "quicktime_common.h"
#include "materialsystem/itexture.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/MaterialSystemUtil.h"
// -----------------------------------------------------------------------------
// Texture regenerator - callback to get new movie pixels into the texture
// -----------------------------------------------------------------------------
class CQuicktimeMaterialRGBTextureRegenerator : public ITextureRegenerator
{
public:
CQuicktimeMaterialRGBTextureRegenerator();
~CQuicktimeMaterialRGBTextureRegenerator();
void SetSourceGWorld( GWorldPtr theGWorld, int nWidth, int nHeight );
// Inherited from ITextureRegenerator
virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect );
virtual void Release();
private:
GWorldPtr m_SrcGWorld;
int m_nSourceWidth;
int m_nSourceHeight;
};
// -----------------------------------------------------------------------------
// Class used to play a QuickTime video onto a texture
// -----------------------------------------------------------------------------
class CQuickTimeMaterial : public IVideoMaterial
{
public:
CQuickTimeMaterial();
~CQuickTimeMaterial();
static const int MAX_QT_FILENAME_LEN = 255;
static const int MAX_MATERIAL_NAME_LEN = 255;
static const int TEXTURE_SIZE_ALIGNMENT = 8;
// Initializes, shuts down the material
bool Init( const char *pMaterialName, const char *pFileName, VideoPlaybackFlags_t flags );
void Shutdown();
// Video information functions
virtual const char *GetVideoFileName(); // Gets the file name of the video this material is playing
virtual VideoResult_t GetLastResult(); // Gets detailed info on the last operation
virtual VideoFrameRate_t &GetVideoFrameRate(); // Returns the frame rate of the associated video in FPS
// Audio Functions
virtual bool HasAudio(); // Query if the video has an audio track
virtual bool SetVolume( float fVolume ); // Adjust the playback volume
virtual float GetVolume(); // Query the current volume
virtual void SetMuted( bool bMuteState ); // Mute/UnMutes the audio playback
virtual bool IsMuted(); // Query muted status
virtual VideoResult_t SoundDeviceCommand( VideoSoundDeviceOperation_t operation, void *pDevice = nullptr, void *pData = nullptr ); // Assign Sound Device for this Video Material
// Video playback state functions
virtual bool IsVideoReadyToPlay(); // Queries if the video material was initialized successfully and is ready for playback, but not playing or finished
virtual bool IsVideoPlaying(); // Is the video currently playing (and needs update calls, etc)
virtual bool IsNewFrameReady(); // Do we have a new frame to get & display?
virtual bool IsFinishedPlaying(); // Have we reached the end of the movie
virtual bool StartVideo(); // Starts the video playing
virtual bool StopVideo(); // Terminates the video playing
virtual void SetLooping( bool bLoopVideo ); // Sets the video to loop (or not)
virtual bool IsLooping(); // Queries if the video is looping
virtual void SetPaused( bool bPauseState ); // Pauses or Unpauses video playback
virtual bool IsPaused(); // Queries if the video is paused
// Position in playback functions
virtual float GetVideoDuration(); // Returns the duration of the associated video in seconds
virtual int GetFrameCount(); // Returns the total number of (unique) frames in the video
virtual bool SetFrame( int FrameNum ); // Sets the current frame # in the video to play next
virtual int GetCurrentFrame(); // Gets the current frame # for the video playback, 0 Based
virtual bool SetTime( float flTime ); // Sets the video playback to specified time (in seconds)
virtual float GetCurrentVideoTime(); // Gets the current time in the video playback
// Update function
virtual bool Update(); // Updates the video frame to reflect the time passed, true = new frame available
// Material / Texture Info functions
virtual IMaterial *GetMaterial(); // Gets the IMaterial associated with an video material
virtual void GetVideoTexCoordRange( float *pMaxU, float *pMaxV ) ; // Returns the max texture coordinate of the video portion of the material surface ( 0.0, 0.0 to U, V )
virtual void GetVideoImageSize( int *pWidth, int *pHeight ); // Returns the frame size of the Video Image Frame in pixels ( the stored in a subrect of the material itself)
private:
friend class CQuicktimeMaterialRGBTextureRegenerator;
void Reset(); // clears internal state
void SetQTFileName( const char *theQTMovieFileName );
VideoResult_t SetResult( VideoResult_t status );
// Initializes, shuts down the video stream
void OpenQTMovie( const char *theQTMovieFileName );
void CloseQTFile();
// Initializes, shuts down the procedural texture
void CreateProceduralTexture( const char *pTextureName );
void DestroyProceduralTexture();
// Initializes, shuts down the procedural material
void CreateProceduralMaterial( const char *pMaterialName );
void DestroyProceduralMaterial();
CQuicktimeMaterialRGBTextureRegenerator m_TextureRegen;
VideoResult_t m_LastResult;
CMaterialReference m_Material; // Ref to Material used for rendering the video frame
CTextureReference m_Texture; // Ref to the renderable texture which contains the most recent video frame (in a sub-rect)
float m_TexCordU; // Max U texture coordinate of the texture sub-rect which holds the video frame
float m_TexCordV; // Max V texture coordinate of the texture sub-rect which holds the video frame
int m_VideoFrameWidth; // Size of the movie frame in pixels
int m_VideoFrameHeight;
char *m_pFileName; // resolved filename of the movie being played
VideoPlaybackFlags_t m_PlaybackFlags; // option flags user supplied
bool m_bInitCalled;
bool m_bMovieInitialized;
bool m_bMoviePlaying;
bool m_bMovieFinishedPlaying;
bool m_bMoviePaused;
bool m_bLoopMovie;
bool m_bHasAudio;
bool m_bMuted;
float m_CurrentVolume;
// QuickTime Stuff
Movie m_QTMovie;
TimeScale m_QTMovieTimeScale; // Units per second
TimeValue m_QTMovieDuration; // movie duration in TimeScale Units Per Second
float m_QTMovieDurationinSec; // movie duration in seconds
VideoFrameRate_t m_QTMovieFrameRate; // Frame Rate of movie
int m_QTMovieFrameCount;
Rect m_QTMovieRect;
GWorldPtr m_MovieGWorld;
QTAudioContextRef m_AudioContext;
TimeValue m_MovieFirstFrameTime;
TimeValue m_NextInterestingTimeToPlay;
TimeValue m_MoviePauseTime;
};
#endif // QUICKTIME_MATERIAL_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,263 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//----------------------------------------------------------------------------------------
#ifndef QUICKTIME_RECORDER_H
#define QUICKTIME_RECORDER_H
#ifdef _WIN32
#pragma once
#endif
//--------------------------------------------------------------------------------
#if defined( OSX )
#include <quicktime/QTML.h>
#include <quicktime/Movies.h>
#include <quicktime/QuickTimeComponents.h>
#elif defined( WIN32 )
#include "QTML.h"
#include "Movies.h"
#include "QuickTimeComponents.h"
#else
#error "Quicktime encoding is not supported on this platform"
#endif
#include "video/ivideoservices.h"
#include "video_macros.h"
#include "quicktime_common.h"
// comment out to prevent logging of creation data
//#define LOG_ENCODER_OPERATIONS
//#define LOG_ENCODER_AUDIO_OPERATIONS
// comment out to log images of frames
//#define LOG_FRAMES_TO_TGA
//#define LOG_FRAMES_TO_TGA_INTERVAL 16
#if defined( LOG_ENCODER_OPERATIONS ) || defined( LOG_ENCODER_AUDIO_OPERATIONS ) || defined ( LOG_FRAMES_TO_TGA ) || defined ( ENABLE_EXTERNAL_ENCODER_LOGGING )
#include <filesystem.h>
#endif
// ------------------------------------------------------------------------
// CQTVideoFileComposer
// Class to manages to creation of a video file from a series of
// supplied bitmap images.
//
// At this time, the time interval between frames must be the same for all
// frames of the movie
// ------------------------------------------------------------------------
class CQTVideoFileComposer
{
public:
static const CodecType DEFAULT_CODEC = kH264CodecType;
static const CodecQ DEFAULT_ENCODE_QUALITY = codecNormalQuality;
static const Fixed DEFAULT_GAMMA = kQTUseSourceGammaLevel;
static const int MIN_AUDIO_SAMPLE_GROUP_SIZE = 64;
static const int MAX_AUDIO_GROUP_SIZE_IN_SEC = 4;
CQTVideoFileComposer();
~CQTVideoFileComposer();
bool CreateNewMovie( const char *fileName, bool hasAudio );
bool SetMovieVideoParameters( int width, int height, VideoFrameRate_t movieFPS, VideoEncodeCodec_t desiredCodec, int encodeQuality, VideoEncodeGamma_t gamma );
bool SetMovieSourceImageParameters( int srcWidth, int srcHeight, VideoEncodeSourceFormat_t srcImageFormat );
bool SetMovieSourceAudioParameters( AudioEncodeSourceFormat_t srcAudioFormat = AudioEncodeSourceFormat::AUDIO_NONE, int audioSampleRate = 0, AudioEncodeOptions_t audioOptions = AudioEncodeOptions::NO_AUDIO_OPTIONS, int audioSampleGroupSize = 0 );
bool AppendVideoFrameToMedia( void *ImageBuffer, int strideAdjustBytes );
bool AppendAudioSamplesToMedia( void *soundBuffer, size_t bufferSize );
bool AbortMovie();
bool FinishMovie( bool SaveMovieToDisk = true );
size_t GetFrameBufferSize() { return m_SrcImageSize; }
bool CheckFilename( const char *filename );
void SetResult( VideoResult_t status );
VideoResult_t GetResult();
bool IsReadyToRecord();
int GetFrameCount() { return m_nFramesAdded; }
int GetSampleCount() { return m_nSamplesAdded; }
VideoFrameRate_t GetFPS() { return m_MovieRecordFPS; }
int GetSampleRate() { return m_AudioSourceFrequency; }
bool HasAudio() { return m_bHasAudioTrack; }
#ifdef ENABLE_EXTERNAL_ENCODER_LOGGING
bool LogMessage( const char *msg );
#endif
private:
enum AudioGrouping_t
{
AG_NONE = 0,
AG_FIXED_SIZE,
AG_PER_FRAME
};
// disable copy constructor and copy assignment
CQTVideoFileComposer( CQTVideoFileComposer &rhs );
CQTVideoFileComposer& operator= ( CQTVideoFileComposer &rhs );
bool CheckForReadyness();
bool BeginMovieCreation();
bool EndMovieCreation( bool saveMovieData );
bool SyncAndFlushAudio();
int GetAudioSampleCountThruFrame( int frameNo );
VideoResult_t m_LastResult;
// Current State of Movie Creation;
bool m_bMovieCreated;
bool m_bHasAudioTrack;
bool m_bMovieConfigured;
bool m_bSourceImagesConfigured;
bool m_bSourceAudioConfigured;
bool m_bComposingMovie;
bool m_bMovieCompleted;
int m_nFramesAdded;
int m_nAudioFramesAdded;
int m_nSamplesAdded;
int m_nSamplesAddedToMedia;
// parameters of the movie to create;
int m_MovieFrameWidth;
int m_MovieFrameHeight;
VideoFrameRate_t m_MovieRecordFPS;
TimeScale m_MovieTimeScale;
TimeValue m_DurationPerFrame;
// Audio recording options
AudioEncodeOptions_t m_AudioOptions; // Option flags specifed by user
AudioGrouping_t m_SampleGrouping; // Mode to group samples
int m_nAudioSampleGroupSize; // number of samples to collect per sample group
int m_AudioSourceFrequency; // Source frequency of the supplied audio
int m_AudioBytesPerSample;
bool m_bBufferSourceAudio;
bool m_bLimitAudioDurationToVideo;
byte *m_srcAudioBuffer; // buffer to hold audio samples
size_t m_srcAudioBufferSize;
size_t m_srcAudioBufferCurrentSize;
int m_AudioSampleFrameCounter;
char *m_FileName;
int m_SrcImageWidth;
int m_SrcImageHeight;
size_t m_SrcImageSize;
int m_ScrImageMaxCompressedSize;
byte *m_SrcImageBuffer;
Handle m_SrcImageCompressedBuffer;
OSType m_SrcPixelFormat;
int m_SrcBytesPerPixel;
OSType m_GWorldPixelFormat;
int m_GWorldBytesPerPixel;
int m_GWorldImageWidth;
int m_GWorldImageHeight;
Handle m_srcSoundDescription;
// parameters used by QuickTime
CodecQ m_EncodeQuality;
CodecType m_VideoCodecToUse;
Fixed m_EncodeGamma;
Rect m_GWorldRect;
GWorldPtr m_theSrcGWorld;
// short m_ResRefNum; // QuickTime Movie Resource Ref number
Handle m_MovieFileDataRef;
OSType m_MovieFileDataRefType;
DataHandler m_MovieFileDataHandler;
Movie m_theMovie;
Track m_theVideoTrack;
Track m_theAudioTrack;
Media m_theVideoMedia;
Media m_theAudioMedia;
#ifdef LOG_ENCODER_OPERATIONS
FileHandle_t m_LogFile;
void LogMsg( PRINTF_FORMAT_STRING const char* pMsg, ... );
#endif
#ifdef LOG_FRAMES_TO_TGA
char m_TGAFileBase[MAX_PATH];
#endif
};
class CQuickTimeVideoRecorder : public IVideoRecorder
{
public:
CQuickTimeVideoRecorder();
~CQuickTimeVideoRecorder();
virtual bool EstimateMovieFileSize( size_t *pEstSize, int movieWidth, int movieHeight, VideoFrameRate_t movieFps, float movieDuration, VideoEncodeCodec_t theCodec, int videoQuality, AudioEncodeSourceFormat_t srcAudioFormat = AudioEncodeSourceFormat::AUDIO_NONE, int audioSampleRate = 0 );
virtual bool CreateNewMovieFile( const char *pFilename, bool hasAudioTrack = false );
virtual bool SetMovieVideoParameters( VideoEncodeCodec_t theCodec, int videoQuality, int movieFrameWidth, int movieFrameHeight, VideoFrameRate_t movieFPS, VideoEncodeGamma_t gamma = VideoEncodeGamma::NO_GAMMA_ADJUST );
virtual bool SetMovieSourceImageParameters( VideoEncodeSourceFormat_t srcImageFormat, int imgWidth, int imgHeight );
virtual bool SetMovieSourceAudioParameters( AudioEncodeSourceFormat_t srcAudioFormat = AudioEncodeSourceFormat::AUDIO_NONE, int audioSampleRate = 0, AudioEncodeOptions_t audioOptions = AudioEncodeOptions::NO_AUDIO_OPTIONS, int audioSampleGroupSize = 0 );
virtual bool IsReadyToRecord();
virtual VideoResult_t GetLastResult();
virtual bool AppendVideoFrame( void *pFrameBuffer, int nStrideAdjustBytes = 0 );
virtual bool AppendAudioSamples( void *pSampleBuffer, size_t sampleSize );
virtual int GetFrameCount();
virtual int GetSampleCount();
virtual int GetSampleRate();
virtual VideoFrameRate_t GetFPS();
virtual bool AbortMovie();
virtual bool FinishMovie( bool SaveMovieToDisk = true );
#ifdef ENABLE_EXTERNAL_ENCODER_LOGGING
virtual bool LogMessage( const char *msg );
#endif
private:
void SetResult( VideoResult_t resultCode );
float GetDataRate( int quality, int width, int height );
CQTVideoFileComposer *m_pEncoder;
VideoResult_t m_LastResult;
bool m_bHasAudio;
bool m_bMovieFinished;
};
#endif // QUICKTIME_RECORDER_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,128 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef QUICKTIME_VIDEO_H
#define QUICKTIME_VIDEO_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
class IFileSystem;
class IMaterialSystem;
class CQuickTimeMaterial;
//-----------------------------------------------------------------------------
// Global interfaces - you already did the needed includes, right?
//-----------------------------------------------------------------------------
extern IFileSystem *g_pFileSystem;
extern IMaterialSystem *materials;
//-----------------------------------------------------------------------------
// Quicktime includes - conditional compilation on #define QUICKTIME in VPC
// The intent is to have a default functionality fallback if not defined
// which provides a dynamically generated texture (moving line on background)
//-----------------------------------------------------------------------------
#if defined ( OSX )
#include <quicktime/QTML.h>
#include <quicktime/Movies.h>
#elif defined ( WIN32 )
#include <QTML.h>
#include <Movies.h>
#include <windows.h>
#elif
#error "Quicktime not supported on this target platform"
#endif
#include "video/ivideoservices.h"
#include "videosubsystem.h"
#include "utlvector.h"
// -----------------------------------------------------------------------------
// CQuickTimeVideoSubSystem - Implementation of IVideoSubSystem
// -----------------------------------------------------------------------------
class CQuickTimeVideoSubSystem : public CTier2AppSystem< IVideoSubSystem >
{
typedef CTier2AppSystem< IVideoSubSystem > BaseClass;
public:
CQuickTimeVideoSubSystem();
~CQuickTimeVideoSubSystem();
// Inherited from IAppSystem
virtual bool Connect( CreateInterfaceFn factory );
virtual void Disconnect();
virtual void *QueryInterface( const char *pInterfaceName );
virtual InitReturnVal_t Init();
virtual void Shutdown();
// Inherited from IVideoSubSystem
// SubSystem Identification functions
virtual VideoSystem_t GetSystemID();
virtual VideoSystemStatus_t GetSystemStatus();
virtual VideoSystemFeature_t GetSupportedFeatures();
virtual const char *GetVideoSystemName();
// Setup & Shutdown Services
virtual bool InitializeVideoSystem( IVideoCommonServices *pCommonServices );
virtual bool ShutdownVideoSystem();
virtual VideoResult_t VideoSoundDeviceCMD( VideoSoundDeviceOperation_t operation, void *pDevice = nullptr, void *pData = nullptr );
// get list of file extensions and features we support
virtual int GetSupportedFileExtensionCount();
virtual const char *GetSupportedFileExtension( int num );
virtual VideoSystemFeature_t GetSupportedFileExtensionFeatures( int num );
// Video Playback and Recording Services
virtual VideoResult_t PlayVideoFileFullScreen( const char *filename, void *mainWindow, int windowWidth, int windowHeight, int desktopWidth, int desktopHeight, bool windowed, float forcedMinTime, VideoPlaybackFlags_t playbackFlags );
// Create/destroy a video material
virtual IVideoMaterial *CreateVideoMaterial( const char *pMaterialName, const char *pVideoFileName, VideoPlaybackFlags_t flags );
virtual VideoResult_t DestroyVideoMaterial( IVideoMaterial *pVideoMaterial );
// Create/destroy a video encoder
virtual IVideoRecorder *CreateVideoRecorder();
virtual VideoResult_t DestroyVideoRecorder( IVideoRecorder *pRecorder );
virtual VideoResult_t CheckCodecAvailability( VideoEncodeCodec_t codec );
virtual VideoResult_t GetLastResult();
private:
bool SetupQuickTime();
bool ShutdownQuickTime();
VideoResult_t SetResult( VideoResult_t status );
bool m_bQuickTimeInitialized;
VideoResult_t m_LastResult;
VideoSystemStatus_t m_CurrentStatus;
VideoSystemFeature_t m_AvailableFeatures;
IVideoCommonServices *m_pCommonServices;
CUtlVector< IVideoMaterial* > m_MaterialList;
CUtlVector< IVideoRecorder* > m_RecorderList;
static const VideoSystemFeature_t DEFAULT_FEATURE_SET;
};
#endif // QUICKTIME_VIDEO_H

View File

@@ -0,0 +1,84 @@
//-----------------------------------------------------------------------------
// video_quicktime.vpc
//
// Project Script
// Created by: Matt Pritchard
//
// Description: Quicktime video sub-system (for video services system)
//
//-----------------------------------------------------------------------------
$Macro SRCDIR ".."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
$Configuration
{
$Compiler
{
// Win32 - need to point to Quicktime 7 for Win SDK directory so that dependant includes will work
$AdditionalIncludeDirectories "$BASE,..\common\quicktime_win32\" [$WIN32]
$AdditionalIncludeDirectories "$BASE;$SRCDIR\dx9sdk\include" [$WIN32]
}
$Linker
{
$IgnoreImportLibrary "Yes" [$WIN32]
$AdditionalDependencies "$BASE vfw32.lib" [$WIN32]
$SystemLibraries "iconv" [$OSXALL]
$SystemFrameworks "Quicktime;Carbon" [$OSXALL]
$AdditionalLibraryDirectories "$BASE;$SRCDIR\dx9sdk\lib" [$WIN32]
}
}
$Configuration "Debug"
{
$General
{
$OutputDirectory "Debug_Video_Quicktime" [$WINDOWS]
$IntermediateDirectory "Debug_Video_Quicktime" [$WINDOWS]
}
}
$Configuration "Release"
{
$General
{
$OutputDirectory "Release_Video_Quicktime" [$WINDOWS]
$IntermediateDirectory "Release_Video_Quicktime" [$WINDOWS]
}
}
$Project "video_quicktime"
{
$Folder "Source Files" [$OSXALL||$WIN32]
{
$file "quicktime_video.cpp"
$file "quicktime_material.cpp"
$file "quicktime_recorder.cpp"
}
$Folder "Header Files" [$OSXALL||$WIN32]
{
$file "videosubsystem.h"
$file "video_macros.h"
$file "quicktime_common.h"
$file "quicktime_video.h"
$file "quicktime_material.h"
$file "quicktime_recorder.h"
$file "$SRCDIR\public\pixelwriter.h"
}
$Folder "Link Libraries"
{
$Lib tier2
$File "$SRCDIR\lib\common\quicktime\QTMLClient.lib" [$WIN32]
$File "$SRCDIR\DX9SDK\lib\dsound.lib" [$WIN32]
$File "$SRCDIR\DX9SDK\lib\dxguid.lib" [$WIN32]
}
}