summaryrefslogtreecommitdiff
path: root/utils/xbox/xbox_loader/xmvhelper.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/xbox/xbox_loader/xmvhelper.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/xbox/xbox_loader/xmvhelper.cpp')
-rw-r--r--utils/xbox/xbox_loader/xmvhelper.cpp788
1 files changed, 788 insertions, 0 deletions
diff --git a/utils/xbox/xbox_loader/xmvhelper.cpp b/utils/xbox/xbox_loader/xmvhelper.cpp
new file mode 100644
index 0000000..74060de
--- /dev/null
+++ b/utils/xbox/xbox_loader/xmvhelper.cpp
@@ -0,0 +1,788 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//-----------------------------------------------------------------------------
+// File: WMVPlayer.cpp
+//
+// Desc: This helper class provides simple WMV decoding and playback
+// functionality. It will be expanded as new playback methods are
+// exposed
+//
+// Hist: 2.7.03 - Created, based on work by Jeff Sullivan
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+#include "xbox_loader.h"
+#include <xtl.h>
+#include "XMVHelper.h"
+#include "XBUtil.h"
+#include <stdio.h>
+
+
+// Funtion Prototypes for packet loading functions for loading from a file.
+HRESULT CALLBACK GetNextPacket( DWORD dwContext,
+ void **ppPacket,
+ DWORD* pOffsetToNextPacket );
+
+HRESULT CALLBACK ReleasePreviousPacket( DWORD dwContext,
+ LONGLONG llNextReadByteOffset,
+ DWORD dwNextPacketSize );
+
+// Funtion Prototypes for packet loading functions for loading from a block of memory.
+HRESULT CALLBACK GetNextMemoryPacket( DWORD dwContext,
+ void **ppPacket,
+ DWORD* pOffsetToNextPacket );
+
+HRESULT CALLBACK ReleasePreviousMemoryPacket( DWORD dwContext,
+ LONGLONG llNextReadByteOffset,
+ DWORD dwNextPacketSize );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CXMVPlayer()
+// Desc: Constructor for CXMVPlayer
+//-----------------------------------------------------------------------------
+CXMVPlayer::CXMVPlayer()
+{
+ m_pXMVDecoder = NULL;
+ ZeroMemory( &m_VideoDesc, sizeof( m_VideoDesc ) );
+ ZeroMemory( &m_AudioDesc, sizeof( m_AudioDesc ) );
+ for ( UINT i=0; i<XMVPLAYER_NUMTEXTURES; i++ )
+ {
+ m_pTextures[i] = NULL;
+ }
+
+ m_dwCurrentFrame = -1; // Will be zero after we decode the first frame.
+
+ m_bPlaying = FALSE;
+ m_bOverlaysEnabled = FALSE;
+
+ m_loadContext.hFile = INVALID_HANDLE_VALUE;
+ m_loadContext.pInputBuffer = 0;
+ m_physicalBuffer = 0;
+ m_bError = FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CXMVPlayer()
+// Desc: Destructor for CXMVPlayer
+//-----------------------------------------------------------------------------
+CXMVPlayer::~CXMVPlayer()
+{
+ Destroy();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: Destroy()
+// Desc: Free all resources and clear are resource pointers and handles.
+//-----------------------------------------------------------------------------
+HRESULT CXMVPlayer::Destroy()
+{
+ // Disable overlays if we were using them.
+ if ( m_bOverlaysEnabled )
+ {
+ m_pDevice->EnableOverlay( FALSE );
+ m_bOverlaysEnabled = FALSE;
+ }
+
+ // Free the XMV decoder.
+ if ( NULL != m_pXMVDecoder )
+ {
+ m_pXMVDecoder->CloseDecoder();
+ m_pXMVDecoder = NULL;
+ }
+
+ ZeroMemory( &m_VideoDesc, sizeof( m_VideoDesc ) );
+ ZeroMemory( &m_AudioDesc, sizeof( m_AudioDesc ) );
+
+ // Release our textures.
+ for ( UINT i=0; i<XMVPLAYER_NUMTEXTURES; i++ )
+ {
+ if ( m_pTextures[i] )
+ m_pTextures[i]->Release();
+ m_pTextures[i] = 0;
+ }
+
+ m_dwCurrentFrame = -1;
+ m_dwStartTime = 0;
+
+ m_bPlaying = FALSE;
+
+ // Release any file handles we were using.
+ if( INVALID_HANDLE_VALUE != m_loadContext.hFile )
+ {
+ CloseHandle( m_loadContext.hFile );
+ m_loadContext.hFile = INVALID_HANDLE_VALUE;
+ }
+
+ // Free up memory used for playing a movie from memory.
+ if ( m_loadContext.pInputBuffer )
+ {
+ free( m_loadContext.pInputBuffer );
+ m_loadContext.pInputBuffer = 0;
+ }
+
+ // Be sure to release the physical memory last!
+ if( m_physicalBuffer )
+ {
+ XPhysicalFree( m_physicalBuffer );
+ m_physicalBuffer = 0;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: FinishOpeningFile()
+// Desc: Helper function for the three Open functions. Enables the audio streams,
+// initializes the video descriptor, and allocates textures if needed.
+//-----------------------------------------------------------------------------
+HRESULT CXMVPlayer::FinishOpeningFile( D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures )
+{
+ assert( format == D3DFMT_YUY2 || format == D3DFMT_LIN_A8R8G8B8 );
+ assert( XMVPLAYER_NUMTEXTURES >= 2);
+
+ HRESULT hr = S_OK;
+
+ m_pXMVDecoder->GetVideoDescriptor( &m_VideoDesc );
+
+ // Enable the audio streams
+ for ( unsigned i=0; i < m_VideoDesc.AudioStreamCount; i++ )
+ {
+ m_pXMVDecoder->GetAudioDescriptor( i, &m_AudioDesc );
+ hr = m_pXMVDecoder->EnableAudioStream( i, 0, NULL, NULL);
+ if ( FAILED( hr ) )
+ {
+ XBUtil_DebugPrint( "Unable to enable audio stream 0 (error %x)\n", hr );
+ Destroy();
+ return hr;
+ }
+ }
+
+ for ( int i = 0; i < XMVPLAYER_NUMTEXTURES; i++ )
+ {
+ m_pTextures[i] = 0;
+ if ( bAllocateTextures )
+ {
+ hr = pDevice->CreateTexture( m_VideoDesc.Width, m_VideoDesc.Height, 1, 0, format, 0, &m_pTextures[i] );
+ if ( FAILED( hr ) )
+ {
+ XBUtil_DebugPrint( "Unable to create texture %d (error %x)\n", i, hr );
+ Destroy();
+ return hr;
+ }
+ }
+ }
+
+ // Initialize what texture we are decoding to, if decoding for texture mapping.
+ m_nDecodeTextureIndex = 0;
+
+ // Initialize the various texture pointers for use when decoding for overlays.
+ pShowingTexture = m_pTextures[0];
+ pDecodingTexture = m_pTextures[1];
+ pSubmittedTexture = 0;
+
+ m_bPlaying = TRUE;
+ m_dwStartTime = GetTickCount();
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: OpenFile()
+// Desc: Create an XMV decoder object that reads from a file.
+//-----------------------------------------------------------------------------
+HRESULT CXMVPlayer::OpenFile( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures )
+{
+ HRESULT hr = S_OK;
+
+ m_bError = FALSE;
+
+ if ( NULL == lpFilename || NULL == pDevice )
+ {
+ XBUtil_DebugPrint( "Bad parameter to OpenFile()\n" );
+ m_bError = TRUE;
+ return E_FAIL;
+ }
+
+ hr = XMVDecoder_CreateDecoderForFile( XMVFLAG_SYNC_ON_NEXT_VBLANK, ( CHAR* )lpFilename, &m_pXMVDecoder );
+ if ( FAILED( hr ) )
+ {
+ XBUtil_DebugPrint( "Unable to create XMV Decoder for %s (error: %x)\n", lpFilename, hr );
+ m_bError = TRUE;
+ return hr;
+ }
+
+ hr = FinishOpeningFile( format, pDevice, bAllocateTextures );
+
+ if ( FAILED( hr ) )
+ {
+ m_bError = TRUE;
+ }
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: OpenFileForPackets()
+// Desc: Create an XMV decoder object that uses the packet reading interface.
+// Currently this just reads from a file, but it can be altered to read from
+// custom formats, start partway through a file, etc.
+//-----------------------------------------------------------------------------
+HRESULT CXMVPlayer::OpenFileForPackets( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures )
+{
+ HRESULT hr = S_OK;
+
+ // We need to read in the first 4K of data for the XMV player to initialize
+ // itself from. This is most conveniently read as an array of DWORDS.
+ DWORD first4Kbytes[4096 / sizeof( DWORD )];
+
+ // Clear entire context struct to zero
+ ZeroMemory( &m_loadContext, sizeof( m_loadContext ) );
+
+ // Open the input file.
+ m_loadContext.hFile = CreateFile( lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
+ NULL );
+
+ if( m_loadContext.hFile == INVALID_HANDLE_VALUE )
+ {
+ Destroy();
+ return E_INVALIDARG;
+ }
+
+ // Read the first page from the file. We opened it for
+ // overlapped IO so we do a pair of reads.
+ m_loadContext.Overlapped.Offset = 0;
+ m_loadContext.Overlapped.OffsetHigh = 0;
+
+ // Start the read.
+ if( 0 == ReadFile( m_loadContext.hFile, first4Kbytes, sizeof( first4Kbytes ), NULL, &m_loadContext.Overlapped ) )
+ {
+ if( GetLastError() != ERROR_IO_PENDING )
+ {
+ Destroy();
+ return E_FAIL;
+ }
+ }
+
+ // Wait for the read to finish.
+ DWORD dwBytesRead;
+ if( !GetOverlappedResult( m_loadContext.hFile, &m_loadContext.Overlapped, &dwBytesRead, TRUE ) )
+ {
+ Destroy();
+ return E_FAIL;
+ }
+
+ // Check size to make sure input is a valid XMV file.
+ if( dwBytesRead != 4096 )
+ {
+ Destroy();
+ return E_FAIL;
+ }
+
+ // Create an XMV decoder
+ hr = XMVDecoder_CreateDecoderForPackets( XMVFLAG_SYNC_ON_NEXT_VBLANK, first4Kbytes, ( DWORD )&m_loadContext,
+ GetNextPacket, ReleasePreviousPacket, &m_pXMVDecoder );
+ if( FAILED( hr ) )
+ {
+ Destroy();
+ return E_FAIL;
+ }
+
+ // The size of the first packet and the minimum size of the two packet buffers are stored in the
+ // second and third DWORDS of the file. From xmv.h:
+ // * DWORD NextPacketSize // The size of the next packet
+ // * DWORD ThisPacketSize // The size of this packet
+ // * DWORD MaxPacketSize // The size of the largest packet in the file
+ DWORD dwThisPacketSize = first4Kbytes[1];
+ DWORD dwRequiredPacketSize = first4Kbytes[2];
+
+ // Check for illegal parameters.
+ if( dwThisPacketSize > dwRequiredPacketSize )
+ {
+ Destroy();
+ return E_FAIL;
+ }
+
+ // XPhysicalAlloc is used so that 5.1 or compressed audio streams can be played.
+ m_physicalBuffer = ( BYTE* )XPhysicalAlloc( dwRequiredPacketSize * 2, MAXULONG_PTR, 0, PAGE_READWRITE );
+
+ // Save our information.
+ m_loadContext.dwPacketSize = dwRequiredPacketSize;
+ m_loadContext.pLoadingPacket = m_physicalBuffer;
+ m_loadContext.pDecodingPacket = m_physicalBuffer + dwRequiredPacketSize;
+
+ // Read the first packet. We wind up re-reading the first 4096
+ // bytes but it makes the logic for figuring out how much we read
+ // a little bit easier...
+ m_loadContext.Overlapped.Offset = 0;
+ m_loadContext.Overlapped.OffsetHigh = 0;
+
+ if( 0 == ReadFile( m_loadContext.hFile, m_physicalBuffer, dwThisPacketSize, NULL,
+ &m_loadContext.Overlapped ) )
+ {
+ if( GetLastError() != ERROR_IO_PENDING )
+ {
+ Destroy();
+ return E_FAIL;
+ }
+ }
+
+ // Note - at this point the preceding read has *not* necessarily completed.
+ // Don't try reading anything from that buffer until GetNextPacket has been
+ // successfully called.
+
+ hr = FinishOpeningFile( format, pDevice, bAllocateTextures );
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: OpenMovieFromMemory()
+// Desc: Create an XMV decoder object that uses the packet reading interface to
+// read from a block of memory. To simplify the memory management this function
+// also allocates this block of memory and initializes it from a file.
+//-----------------------------------------------------------------------------
+HRESULT CXMVPlayer::OpenMovieFromMemory( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures )
+{
+ HRESULT hr = S_OK;
+
+ m_bError = FALSE;
+
+ // Read the entire file into memory.
+ void* data;
+ hr = XBUtil_LoadFile( lpFilename, &data, &m_loadContext.inputSize );
+ if ( FAILED( hr ) )
+ {
+ m_bError = TRUE;
+ return hr;
+ }
+
+ m_loadContext.pInputBuffer = ( BYTE* )data;
+
+ // Check size to make sure input is a valid XMV file.
+ if( m_loadContext.inputSize < 4096 )
+ {
+ Destroy();
+ m_bError = TRUE;
+ return E_FAIL;
+ }
+
+ // Get a DWORD pointer to the first 4K - needed by CreateDecoderForPackets
+ DWORD* first4Kbytes = ( DWORD* )data;
+
+ // Create an XMV decoder
+ hr = XMVDecoder_CreateDecoderForPackets( XMVFLAG_SYNC_ON_NEXT_VBLANK, first4Kbytes, ( DWORD )&m_loadContext, GetNextMemoryPacket,
+ ReleasePreviousMemoryPacket, &m_pXMVDecoder );
+ if ( FAILED( hr ) )
+ {
+ Destroy();
+ m_bError = TRUE;
+ return E_FAIL;
+ }
+
+ // The size of the first packet and the minimum size of the two packet buffers are stored in the
+ // second and third DWORDS of the file. From xmv.h:
+ // * DWORD NextPacketSize // The size of the next packet
+ // * DWORD ThisPacketSize // The size of this packet
+ // * DWORD MaxPacketSize // The size of the largest packet in the file
+ DWORD dwThisPacketSize = first4Kbytes[1];
+ DWORD dwRequiredPacketSize = first4Kbytes[2];
+
+ // Check for illegal parameters.
+ if( dwThisPacketSize > dwRequiredPacketSize )
+ {
+ Destroy();
+ m_bError = TRUE;
+ return E_FAIL;
+ }
+
+ // XPhysicalAlloc is used so that 5.1 or compressed audio streams can be played.
+ m_physicalBuffer = ( BYTE* )XPhysicalAlloc( dwRequiredPacketSize * 2, MAXULONG_PTR, 0, PAGE_READWRITE );
+
+ // Save our information for the callback functions.
+ // The size of our two memory blocks.
+ m_loadContext.dwPacketSize = dwRequiredPacketSize;
+ // The addresses of our two memory blocks.
+ m_loadContext.pLoadingPacket = m_physicalBuffer;
+ m_loadContext.pDecodingPacket = m_physicalBuffer + dwRequiredPacketSize;
+
+ // Information about the block of memory the movie is stored in.
+ m_loadContext.pInputBuffer = ( BYTE* )data;
+ m_loadContext.inputSize = m_loadContext.inputSize;
+ m_loadContext.readOffset = 0;
+ m_loadContext.currentPacketSize = dwThisPacketSize;
+
+ hr = FinishOpeningFile( format, pDevice, bAllocateTextures );
+
+ if ( FAILED( hr ) )
+ {
+ m_bError = TRUE;
+ }
+
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: AdvanceFrameForTexturing()
+// Desc: Unpack the appropriate frames of data for use as textures.
+//-----------------------------------------------------------------------------
+LPDIRECT3DTEXTURE8 CXMVPlayer::AdvanceFrameForTexturing( LPDIRECT3DDEVICE8 pDevice )
+{
+ // You must pass bAllocateTextures==TRUE to Open if you're going to use GetTexture/AdvanceFrame.
+ assert( m_pTextures[0] );
+
+ LPDIRECT3DSURFACE8 pSurface;
+ pDecodingTexture->GetSurfaceLevel( 0, &pSurface );
+
+ // Decode some information to the current draw texture.
+ XMVRESULT xr = XMV_NOFRAME;
+ m_pXMVDecoder->GetNextFrame( pSurface, &xr, NULL );
+
+ switch ( xr )
+ {
+ case XMV_NOFRAME:
+ // Do nothing - we didn't get a frame.
+ break;
+
+ case XMV_NEWFRAME:
+ ++m_dwCurrentFrame;
+ // GetNextFrame produced a new frame. So, the texture we were decoding
+ // to becomes available for drawing as a texture.
+ pShowingTexture = pDecodingTexture;
+
+ // Setup for decoding to the next texture.
+ m_nDecodeTextureIndex = ( m_nDecodeTextureIndex + 1 ) % XMVPLAYER_NUMTEXTURES;
+ pDecodingTexture = m_pTextures[ m_nDecodeTextureIndex ];
+ break;
+
+ case XMV_ENDOFFILE:
+ m_bPlaying = FALSE;
+ break;
+
+ case XMV_FAIL:
+ // Data corruption or file read error. We'll treat that the same as
+ // end of file.
+ m_bPlaying = FALSE;
+ m_bError = TRUE;
+ break;
+ }
+
+ SAFE_RELEASE( pSurface );
+
+ // If we haven't decoded the first frame then return zero.
+ if ( m_dwCurrentFrame < 0 )
+ return 0;
+
+ return pShowingTexture;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: AdvanceFrameForOverlays()
+// Desc: Unpack the appropriate frames of data for use as an overlay.
+//-----------------------------------------------------------------------------
+LPDIRECT3DTEXTURE8 CXMVPlayer::AdvanceFrameForOverlays( LPDIRECT3DDEVICE8 pDevice )
+{
+ // You must pass bAllocateTextures==TRUE to Open if you're going to use GetTexture/AdvanceFrame.
+ assert( m_pTextures[0] );
+
+ // You have to call CXMVPlayer::EnableOverlays() if you are going to use overlays.
+ assert( m_bOverlaysEnabled );
+
+ // If a texture has been submitted to be used as an overlay then we have to
+ // wait for GetUpdateOverlayState() to return TRUE before we can assume that
+ // the previous texture has *stopped* being displayed. Once GetUpdateOverlayState()
+ // returns TRUE then we know that pSubmittedTexture is being displayed, which
+ // means that, pShowingTexture is available as a decoding target.
+ if ( pSubmittedTexture )
+ {
+ // If GetOverlayUpdateStatus() returns FALSE then we can still proceed and
+ // call GetNextFrame(), but we will pass NULL for the surface parameter.
+ // Some work will still be done, but none of the surfaces will be altered.
+ if ( pDevice->GetOverlayUpdateStatus() )
+ {
+ // The call to UpdateOverlay() with pSubmittedTexture must have taken
+ // effect now, so pShowingTexture is available as a decoding target.
+ assert( !pDecodingTexture );
+ pDecodingTexture = pShowingTexture;
+ pShowingTexture = pSubmittedTexture;
+ pSubmittedTexture = NULL;
+ }
+ }
+
+ LPDIRECT3DSURFACE8 pSurface = NULL;
+ if ( pDecodingTexture )
+ pDecodingTexture->GetSurfaceLevel( 0, &pSurface );
+
+ // Decode some information to the current draw texture, which may be NULL.
+ // pDecodingTexture will be NULL if one texture has been submitted as a new
+ // overlay but the other one is still being displayed as an overlay.
+ // If pSurface is NULL GetNextFrame() will still do some work.
+ XMVRESULT xr = XMV_NOFRAME;
+ m_pXMVDecoder->GetNextFrame( pSurface, &xr, NULL );
+
+ switch ( xr )
+ {
+ case XMV_NOFRAME:
+ // Do nothing - we didn't get a frame.
+ break;
+
+ case XMV_NEWFRAME:
+ ++m_dwCurrentFrame;
+ // GetNextFrame produced a new frame. So, the texture we were decoding
+ // to becomes available for displaying as an overlay.
+
+ // The other texture is not ready to be a decoding target. It is still
+ // being displayed as an overlay. So, we assign the newly decoded
+ // texture to pSubmittedTexture for the program to submit as an overlay,
+ // but we don't yet move the previously submitted texture from pShowing
+ // to pDecoding. That happens on a subsequent call to this function, after
+ // GetOverlayUpdateStatus() returns TRUE to tell us that there are no
+ // overlay swaps pending.
+ assert( pDecodingTexture );
+ assert( !pSubmittedTexture );
+ pSubmittedTexture = pDecodingTexture;
+ pDecodingTexture = NULL;
+ break;
+
+ case XMV_ENDOFFILE:
+ m_bPlaying = FALSE;
+ break;
+
+ case XMV_FAIL:
+ // Data corruption or file read error. We'll treat that the same as
+ // end of file.
+ m_bPlaying = FALSE;
+ m_bError = TRUE;
+ break;
+ }
+
+ SAFE_RELEASE( pSurface );
+
+ // If we just unpacked a new frame then we return that texture
+ // and the program must call UpdateOverlay() with the surface
+ // from that texture.
+ // If we didn't unpack a frame then the program should do nothing -
+ // the previous overlay will continue to be displayed.
+ if ( XMV_NEWFRAME == xr )
+ return pSubmittedTexture;
+
+ // No new frame to display.
+ return 0;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: TerminatePlayback()
+// Desc: Calls XMVDecoder::TerminatePlayback()
+//-----------------------------------------------------------------------------
+void CXMVPlayer::TerminatePlayback()
+{
+ m_pXMVDecoder->TerminatePlayback();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: Play()
+// Desc: Calls XMVDecoder::Play() to play the entire movie.
+//-----------------------------------------------------------------------------
+HRESULT CXMVPlayer::Play( DWORD Flags, RECT* pRect )
+{
+ // You have to call Open before calling Play.
+ assert( m_pXMVDecoder );
+
+ // Don't pass bAllocateTextures==TRUE to Open if you're going to use Play.
+ assert( !m_pTextures[0] );
+
+ return m_pXMVDecoder->Play( Flags, pRect );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: EnableOverlays()
+// Desc: Enable the overlay planes for playing the movie in them, and record
+// that the overlays should be disabled when Destroy() is called.
+//-----------------------------------------------------------------------------
+void CXMVPlayer::EnableOverlays( LPDIRECT3DDEVICE8 pDevice )
+{
+ m_pDevice = pDevice;
+ pDevice->EnableOverlay( TRUE );
+ m_bOverlaysEnabled = TRUE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: GetNextPacket()
+// Desc: Callback function to get next packet from a file
+//-----------------------------------------------------------------------------
+static HRESULT CALLBACK GetNextPacket( DWORD dwContext, VOID** ppPacket,
+ DWORD* pOffsetToNextPacket )
+{
+ LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext;
+ if( NULL == pContext )
+ return E_FAIL;
+
+ // If the next packet is fully loaded then return it,
+ // otherwise return NULL.
+ DWORD dwBytesRead;
+ if( GetOverlappedResult( pContext->hFile, &pContext->Overlapped,
+ &dwBytesRead, FALSE ) )
+ {
+ // Make the old decoding packet pending.
+ pContext->pPendingReleasePacket = pContext->pDecodingPacket;
+ pContext->pDecodingPacket = pContext->pLoadingPacket;
+ pContext->pLoadingPacket = NULL;
+
+ // Offset to the next packet.
+ *pOffsetToNextPacket = dwBytesRead;
+
+ // Set *ppPacket to the data we just loaded.
+ *ppPacket = pContext->pDecodingPacket;
+ }
+ else
+ {
+ DWORD dwError = GetLastError();
+
+ // If we're waiting on the IO to finish, just do nothing.
+ if( dwError != ERROR_IO_INCOMPLETE )
+ return HRESULT_FROM_WIN32( dwError );
+
+ *ppPacket = NULL;
+ *pOffsetToNextPacket = 0;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ReleasePreviousPacket()
+// Desc: Callback function to release previous packet from a file
+//-----------------------------------------------------------------------------
+static HRESULT CALLBACK ReleasePreviousPacket( DWORD dwContext, LONGLONG llNextReadByteOffset,
+ DWORD dwNextPacketSize )
+{
+ LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext;
+ if( NULL == pContext )
+ return E_FAIL;
+
+ if( dwNextPacketSize != 0 )
+ {
+ // Start the next load.
+ pContext->Overlapped.Offset = ( DWORD )( llNextReadByteOffset & 0xFFFFFFFF );
+ pContext->Overlapped.OffsetHigh = ( DWORD )( llNextReadByteOffset >> 32 );
+
+ // Check for bad input file - buffer overrun
+ if( dwNextPacketSize > pContext->dwPacketSize )
+ return E_FAIL;
+
+ pContext->pLoadingPacket = pContext->pPendingReleasePacket;
+ pContext->pPendingReleasePacket = NULL;
+
+ if( 0 == ReadFile( pContext->hFile, pContext->pLoadingPacket,
+ dwNextPacketSize, NULL, &pContext->Overlapped ) )
+ {
+ if( GetLastError() != ERROR_IO_PENDING )
+ return HRESULT_FROM_WIN32( GetLastError() );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: GetNextMemoryPacket()
+// Desc: Callback function to get next packet from a file,
+// and setup for the next packet.
+//-----------------------------------------------------------------------------
+static HRESULT CALLBACK GetNextMemoryPacket( DWORD dwContext, VOID** ppPacket,
+ DWORD* pOffsetToNextPacket )
+{
+ LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext;
+ if( NULL == pContext )
+ return E_FAIL;
+
+ DWORD dwBytesRead = pContext->inputSize - pContext->readOffset;
+ if ( pContext->currentPacketSize < dwBytesRead )
+ dwBytesRead = pContext->currentPacketSize;
+
+ memcpy( pContext->pLoadingPacket, pContext->pInputBuffer + pContext->readOffset , dwBytesRead );
+ pContext->readOffset +=dwBytesRead;
+
+ // Swap pointers so that next time we load it goes into the other packet block.
+ BYTE* temp = pContext->pLoadingPacket;
+ pContext->pLoadingPacket = pContext->pDecodingPacket;
+ pContext->pDecodingPacket = temp;
+
+ // Offset to the next packet.
+ *pOffsetToNextPacket = dwBytesRead;
+
+ // Set *ppPacket to the data we just loaded.
+ *ppPacket = pContext->pDecodingPacket;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ReleasePreviousMemoryPacket()
+// Desc: Callback function to release previous packet from a block of memory,
+// and setup for the next packet.
+//-----------------------------------------------------------------------------
+static HRESULT CALLBACK ReleasePreviousMemoryPacket( DWORD dwContext, LONGLONG llNextReadByteOffset,
+ DWORD dwNextPacketSize )
+{
+ LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext;
+ if( NULL == pContext )
+ return E_FAIL;
+
+ // Check for bad input file - buffer overrun
+ if( dwNextPacketSize > pContext->dwPacketSize )
+ return E_FAIL;
+
+ // Record the size of the next packet we are supposed to read, for GetNextMemoryPacket.
+ pContext->currentPacketSize = dwNextPacketSize;
+
+ return S_OK;
+}