diff options
Diffstat (limited to 'utils/xbox/xbox_loader/xmvhelper.cpp')
| -rw-r--r-- | utils/xbox/xbox_loader/xmvhelper.cpp | 788 |
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; +} |