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

788 lines
26 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //-----------------------------------------------------------------------------
  3. // File: WMVPlayer.cpp
  4. //
  5. // Desc: This helper class provides simple WMV decoding and playback
  6. // functionality. It will be expanded as new playback methods are
  7. // exposed
  8. //
  9. // Hist: 2.7.03 - Created, based on work by Jeff Sullivan
  10. //
  11. // Copyright (c) Microsoft Corporation. All rights reserved.
  12. //-----------------------------------------------------------------------------
  13. #include "xbox_loader.h"
  14. #include <xtl.h>
  15. #include "XMVHelper.h"
  16. #include "XBUtil.h"
  17. #include <stdio.h>
  18. // Funtion Prototypes for packet loading functions for loading from a file.
  19. HRESULT CALLBACK GetNextPacket( DWORD dwContext,
  20. void **ppPacket,
  21. DWORD* pOffsetToNextPacket );
  22. HRESULT CALLBACK ReleasePreviousPacket( DWORD dwContext,
  23. LONGLONG llNextReadByteOffset,
  24. DWORD dwNextPacketSize );
  25. // Funtion Prototypes for packet loading functions for loading from a block of memory.
  26. HRESULT CALLBACK GetNextMemoryPacket( DWORD dwContext,
  27. void **ppPacket,
  28. DWORD* pOffsetToNextPacket );
  29. HRESULT CALLBACK ReleasePreviousMemoryPacket( DWORD dwContext,
  30. LONGLONG llNextReadByteOffset,
  31. DWORD dwNextPacketSize );
  32. //-----------------------------------------------------------------------------
  33. // Name: CXMVPlayer()
  34. // Desc: Constructor for CXMVPlayer
  35. //-----------------------------------------------------------------------------
  36. CXMVPlayer::CXMVPlayer()
  37. {
  38. m_pXMVDecoder = NULL;
  39. ZeroMemory( &m_VideoDesc, sizeof( m_VideoDesc ) );
  40. ZeroMemory( &m_AudioDesc, sizeof( m_AudioDesc ) );
  41. for ( UINT i=0; i<XMVPLAYER_NUMTEXTURES; i++ )
  42. {
  43. m_pTextures[i] = NULL;
  44. }
  45. m_dwCurrentFrame = -1; // Will be zero after we decode the first frame.
  46. m_bPlaying = FALSE;
  47. m_bOverlaysEnabled = FALSE;
  48. m_loadContext.hFile = INVALID_HANDLE_VALUE;
  49. m_loadContext.pInputBuffer = 0;
  50. m_physicalBuffer = 0;
  51. m_bError = FALSE;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Name: ~CXMVPlayer()
  55. // Desc: Destructor for CXMVPlayer
  56. //-----------------------------------------------------------------------------
  57. CXMVPlayer::~CXMVPlayer()
  58. {
  59. Destroy();
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Name: Destroy()
  63. // Desc: Free all resources and clear are resource pointers and handles.
  64. //-----------------------------------------------------------------------------
  65. HRESULT CXMVPlayer::Destroy()
  66. {
  67. // Disable overlays if we were using them.
  68. if ( m_bOverlaysEnabled )
  69. {
  70. m_pDevice->EnableOverlay( FALSE );
  71. m_bOverlaysEnabled = FALSE;
  72. }
  73. // Free the XMV decoder.
  74. if ( NULL != m_pXMVDecoder )
  75. {
  76. m_pXMVDecoder->CloseDecoder();
  77. m_pXMVDecoder = NULL;
  78. }
  79. ZeroMemory( &m_VideoDesc, sizeof( m_VideoDesc ) );
  80. ZeroMemory( &m_AudioDesc, sizeof( m_AudioDesc ) );
  81. // Release our textures.
  82. for ( UINT i=0; i<XMVPLAYER_NUMTEXTURES; i++ )
  83. {
  84. if ( m_pTextures[i] )
  85. m_pTextures[i]->Release();
  86. m_pTextures[i] = 0;
  87. }
  88. m_dwCurrentFrame = -1;
  89. m_dwStartTime = 0;
  90. m_bPlaying = FALSE;
  91. // Release any file handles we were using.
  92. if( INVALID_HANDLE_VALUE != m_loadContext.hFile )
  93. {
  94. CloseHandle( m_loadContext.hFile );
  95. m_loadContext.hFile = INVALID_HANDLE_VALUE;
  96. }
  97. // Free up memory used for playing a movie from memory.
  98. if ( m_loadContext.pInputBuffer )
  99. {
  100. free( m_loadContext.pInputBuffer );
  101. m_loadContext.pInputBuffer = 0;
  102. }
  103. // Be sure to release the physical memory last!
  104. if( m_physicalBuffer )
  105. {
  106. XPhysicalFree( m_physicalBuffer );
  107. m_physicalBuffer = 0;
  108. }
  109. return S_OK;
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Name: FinishOpeningFile()
  113. // Desc: Helper function for the three Open functions. Enables the audio streams,
  114. // initializes the video descriptor, and allocates textures if needed.
  115. //-----------------------------------------------------------------------------
  116. HRESULT CXMVPlayer::FinishOpeningFile( D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures )
  117. {
  118. assert( format == D3DFMT_YUY2 || format == D3DFMT_LIN_A8R8G8B8 );
  119. assert( XMVPLAYER_NUMTEXTURES >= 2);
  120. HRESULT hr = S_OK;
  121. m_pXMVDecoder->GetVideoDescriptor( &m_VideoDesc );
  122. // Enable the audio streams
  123. for ( unsigned i=0; i < m_VideoDesc.AudioStreamCount; i++ )
  124. {
  125. m_pXMVDecoder->GetAudioDescriptor( i, &m_AudioDesc );
  126. hr = m_pXMVDecoder->EnableAudioStream( i, 0, NULL, NULL);
  127. if ( FAILED( hr ) )
  128. {
  129. XBUtil_DebugPrint( "Unable to enable audio stream 0 (error %x)\n", hr );
  130. Destroy();
  131. return hr;
  132. }
  133. }
  134. for ( int i = 0; i < XMVPLAYER_NUMTEXTURES; i++ )
  135. {
  136. m_pTextures[i] = 0;
  137. if ( bAllocateTextures )
  138. {
  139. hr = pDevice->CreateTexture( m_VideoDesc.Width, m_VideoDesc.Height, 1, 0, format, 0, &m_pTextures[i] );
  140. if ( FAILED( hr ) )
  141. {
  142. XBUtil_DebugPrint( "Unable to create texture %d (error %x)\n", i, hr );
  143. Destroy();
  144. return hr;
  145. }
  146. }
  147. }
  148. // Initialize what texture we are decoding to, if decoding for texture mapping.
  149. m_nDecodeTextureIndex = 0;
  150. // Initialize the various texture pointers for use when decoding for overlays.
  151. pShowingTexture = m_pTextures[0];
  152. pDecodingTexture = m_pTextures[1];
  153. pSubmittedTexture = 0;
  154. m_bPlaying = TRUE;
  155. m_dwStartTime = GetTickCount();
  156. return hr;
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Name: OpenFile()
  160. // Desc: Create an XMV decoder object that reads from a file.
  161. //-----------------------------------------------------------------------------
  162. HRESULT CXMVPlayer::OpenFile( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures )
  163. {
  164. HRESULT hr = S_OK;
  165. m_bError = FALSE;
  166. if ( NULL == lpFilename || NULL == pDevice )
  167. {
  168. XBUtil_DebugPrint( "Bad parameter to OpenFile()\n" );
  169. m_bError = TRUE;
  170. return E_FAIL;
  171. }
  172. hr = XMVDecoder_CreateDecoderForFile( XMVFLAG_SYNC_ON_NEXT_VBLANK, ( CHAR* )lpFilename, &m_pXMVDecoder );
  173. if ( FAILED( hr ) )
  174. {
  175. XBUtil_DebugPrint( "Unable to create XMV Decoder for %s (error: %x)\n", lpFilename, hr );
  176. m_bError = TRUE;
  177. return hr;
  178. }
  179. hr = FinishOpeningFile( format, pDevice, bAllocateTextures );
  180. if ( FAILED( hr ) )
  181. {
  182. m_bError = TRUE;
  183. }
  184. return hr;
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Name: OpenFileForPackets()
  188. // Desc: Create an XMV decoder object that uses the packet reading interface.
  189. // Currently this just reads from a file, but it can be altered to read from
  190. // custom formats, start partway through a file, etc.
  191. //-----------------------------------------------------------------------------
  192. HRESULT CXMVPlayer::OpenFileForPackets( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures )
  193. {
  194. HRESULT hr = S_OK;
  195. // We need to read in the first 4K of data for the XMV player to initialize
  196. // itself from. This is most conveniently read as an array of DWORDS.
  197. DWORD first4Kbytes[4096 / sizeof( DWORD )];
  198. // Clear entire context struct to zero
  199. ZeroMemory( &m_loadContext, sizeof( m_loadContext ) );
  200. // Open the input file.
  201. m_loadContext.hFile = CreateFile( lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
  202. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
  203. NULL );
  204. if( m_loadContext.hFile == INVALID_HANDLE_VALUE )
  205. {
  206. Destroy();
  207. return E_INVALIDARG;
  208. }
  209. // Read the first page from the file. We opened it for
  210. // overlapped IO so we do a pair of reads.
  211. m_loadContext.Overlapped.Offset = 0;
  212. m_loadContext.Overlapped.OffsetHigh = 0;
  213. // Start the read.
  214. if( 0 == ReadFile( m_loadContext.hFile, first4Kbytes, sizeof( first4Kbytes ), NULL, &m_loadContext.Overlapped ) )
  215. {
  216. if( GetLastError() != ERROR_IO_PENDING )
  217. {
  218. Destroy();
  219. return E_FAIL;
  220. }
  221. }
  222. // Wait for the read to finish.
  223. DWORD dwBytesRead;
  224. if( !GetOverlappedResult( m_loadContext.hFile, &m_loadContext.Overlapped, &dwBytesRead, TRUE ) )
  225. {
  226. Destroy();
  227. return E_FAIL;
  228. }
  229. // Check size to make sure input is a valid XMV file.
  230. if( dwBytesRead != 4096 )
  231. {
  232. Destroy();
  233. return E_FAIL;
  234. }
  235. // Create an XMV decoder
  236. hr = XMVDecoder_CreateDecoderForPackets( XMVFLAG_SYNC_ON_NEXT_VBLANK, first4Kbytes, ( DWORD )&m_loadContext,
  237. GetNextPacket, ReleasePreviousPacket, &m_pXMVDecoder );
  238. if( FAILED( hr ) )
  239. {
  240. Destroy();
  241. return E_FAIL;
  242. }
  243. // The size of the first packet and the minimum size of the two packet buffers are stored in the
  244. // second and third DWORDS of the file. From xmv.h:
  245. // * DWORD NextPacketSize // The size of the next packet
  246. // * DWORD ThisPacketSize // The size of this packet
  247. // * DWORD MaxPacketSize // The size of the largest packet in the file
  248. DWORD dwThisPacketSize = first4Kbytes[1];
  249. DWORD dwRequiredPacketSize = first4Kbytes[2];
  250. // Check for illegal parameters.
  251. if( dwThisPacketSize > dwRequiredPacketSize )
  252. {
  253. Destroy();
  254. return E_FAIL;
  255. }
  256. // XPhysicalAlloc is used so that 5.1 or compressed audio streams can be played.
  257. m_physicalBuffer = ( BYTE* )XPhysicalAlloc( dwRequiredPacketSize * 2, MAXULONG_PTR, 0, PAGE_READWRITE );
  258. // Save our information.
  259. m_loadContext.dwPacketSize = dwRequiredPacketSize;
  260. m_loadContext.pLoadingPacket = m_physicalBuffer;
  261. m_loadContext.pDecodingPacket = m_physicalBuffer + dwRequiredPacketSize;
  262. // Read the first packet. We wind up re-reading the first 4096
  263. // bytes but it makes the logic for figuring out how much we read
  264. // a little bit easier...
  265. m_loadContext.Overlapped.Offset = 0;
  266. m_loadContext.Overlapped.OffsetHigh = 0;
  267. if( 0 == ReadFile( m_loadContext.hFile, m_physicalBuffer, dwThisPacketSize, NULL,
  268. &m_loadContext.Overlapped ) )
  269. {
  270. if( GetLastError() != ERROR_IO_PENDING )
  271. {
  272. Destroy();
  273. return E_FAIL;
  274. }
  275. }
  276. // Note - at this point the preceding read has *not* necessarily completed.
  277. // Don't try reading anything from that buffer until GetNextPacket has been
  278. // successfully called.
  279. hr = FinishOpeningFile( format, pDevice, bAllocateTextures );
  280. return hr;
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Name: OpenMovieFromMemory()
  284. // Desc: Create an XMV decoder object that uses the packet reading interface to
  285. // read from a block of memory. To simplify the memory management this function
  286. // also allocates this block of memory and initializes it from a file.
  287. //-----------------------------------------------------------------------------
  288. HRESULT CXMVPlayer::OpenMovieFromMemory( const CHAR* lpFilename, D3DFORMAT format, LPDIRECT3DDEVICE8 pDevice, BOOL bAllocateTextures )
  289. {
  290. HRESULT hr = S_OK;
  291. m_bError = FALSE;
  292. // Read the entire file into memory.
  293. void* data;
  294. hr = XBUtil_LoadFile( lpFilename, &data, &m_loadContext.inputSize );
  295. if ( FAILED( hr ) )
  296. {
  297. m_bError = TRUE;
  298. return hr;
  299. }
  300. m_loadContext.pInputBuffer = ( BYTE* )data;
  301. // Check size to make sure input is a valid XMV file.
  302. if( m_loadContext.inputSize < 4096 )
  303. {
  304. Destroy();
  305. m_bError = TRUE;
  306. return E_FAIL;
  307. }
  308. // Get a DWORD pointer to the first 4K - needed by CreateDecoderForPackets
  309. DWORD* first4Kbytes = ( DWORD* )data;
  310. // Create an XMV decoder
  311. hr = XMVDecoder_CreateDecoderForPackets( XMVFLAG_SYNC_ON_NEXT_VBLANK, first4Kbytes, ( DWORD )&m_loadContext, GetNextMemoryPacket,
  312. ReleasePreviousMemoryPacket, &m_pXMVDecoder );
  313. if ( FAILED( hr ) )
  314. {
  315. Destroy();
  316. m_bError = TRUE;
  317. return E_FAIL;
  318. }
  319. // The size of the first packet and the minimum size of the two packet buffers are stored in the
  320. // second and third DWORDS of the file. From xmv.h:
  321. // * DWORD NextPacketSize // The size of the next packet
  322. // * DWORD ThisPacketSize // The size of this packet
  323. // * DWORD MaxPacketSize // The size of the largest packet in the file
  324. DWORD dwThisPacketSize = first4Kbytes[1];
  325. DWORD dwRequiredPacketSize = first4Kbytes[2];
  326. // Check for illegal parameters.
  327. if( dwThisPacketSize > dwRequiredPacketSize )
  328. {
  329. Destroy();
  330. m_bError = TRUE;
  331. return E_FAIL;
  332. }
  333. // XPhysicalAlloc is used so that 5.1 or compressed audio streams can be played.
  334. m_physicalBuffer = ( BYTE* )XPhysicalAlloc( dwRequiredPacketSize * 2, MAXULONG_PTR, 0, PAGE_READWRITE );
  335. // Save our information for the callback functions.
  336. // The size of our two memory blocks.
  337. m_loadContext.dwPacketSize = dwRequiredPacketSize;
  338. // The addresses of our two memory blocks.
  339. m_loadContext.pLoadingPacket = m_physicalBuffer;
  340. m_loadContext.pDecodingPacket = m_physicalBuffer + dwRequiredPacketSize;
  341. // Information about the block of memory the movie is stored in.
  342. m_loadContext.pInputBuffer = ( BYTE* )data;
  343. m_loadContext.inputSize = m_loadContext.inputSize;
  344. m_loadContext.readOffset = 0;
  345. m_loadContext.currentPacketSize = dwThisPacketSize;
  346. hr = FinishOpeningFile( format, pDevice, bAllocateTextures );
  347. if ( FAILED( hr ) )
  348. {
  349. m_bError = TRUE;
  350. }
  351. return hr;
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Name: AdvanceFrameForTexturing()
  355. // Desc: Unpack the appropriate frames of data for use as textures.
  356. //-----------------------------------------------------------------------------
  357. LPDIRECT3DTEXTURE8 CXMVPlayer::AdvanceFrameForTexturing( LPDIRECT3DDEVICE8 pDevice )
  358. {
  359. // You must pass bAllocateTextures==TRUE to Open if you're going to use GetTexture/AdvanceFrame.
  360. assert( m_pTextures[0] );
  361. LPDIRECT3DSURFACE8 pSurface;
  362. pDecodingTexture->GetSurfaceLevel( 0, &pSurface );
  363. // Decode some information to the current draw texture.
  364. XMVRESULT xr = XMV_NOFRAME;
  365. m_pXMVDecoder->GetNextFrame( pSurface, &xr, NULL );
  366. switch ( xr )
  367. {
  368. case XMV_NOFRAME:
  369. // Do nothing - we didn't get a frame.
  370. break;
  371. case XMV_NEWFRAME:
  372. ++m_dwCurrentFrame;
  373. // GetNextFrame produced a new frame. So, the texture we were decoding
  374. // to becomes available for drawing as a texture.
  375. pShowingTexture = pDecodingTexture;
  376. // Setup for decoding to the next texture.
  377. m_nDecodeTextureIndex = ( m_nDecodeTextureIndex + 1 ) % XMVPLAYER_NUMTEXTURES;
  378. pDecodingTexture = m_pTextures[ m_nDecodeTextureIndex ];
  379. break;
  380. case XMV_ENDOFFILE:
  381. m_bPlaying = FALSE;
  382. break;
  383. case XMV_FAIL:
  384. // Data corruption or file read error. We'll treat that the same as
  385. // end of file.
  386. m_bPlaying = FALSE;
  387. m_bError = TRUE;
  388. break;
  389. }
  390. SAFE_RELEASE( pSurface );
  391. // If we haven't decoded the first frame then return zero.
  392. if ( m_dwCurrentFrame < 0 )
  393. return 0;
  394. return pShowingTexture;
  395. }
  396. //-----------------------------------------------------------------------------
  397. // Name: AdvanceFrameForOverlays()
  398. // Desc: Unpack the appropriate frames of data for use as an overlay.
  399. //-----------------------------------------------------------------------------
  400. LPDIRECT3DTEXTURE8 CXMVPlayer::AdvanceFrameForOverlays( LPDIRECT3DDEVICE8 pDevice )
  401. {
  402. // You must pass bAllocateTextures==TRUE to Open if you're going to use GetTexture/AdvanceFrame.
  403. assert( m_pTextures[0] );
  404. // You have to call CXMVPlayer::EnableOverlays() if you are going to use overlays.
  405. assert( m_bOverlaysEnabled );
  406. // If a texture has been submitted to be used as an overlay then we have to
  407. // wait for GetUpdateOverlayState() to return TRUE before we can assume that
  408. // the previous texture has *stopped* being displayed. Once GetUpdateOverlayState()
  409. // returns TRUE then we know that pSubmittedTexture is being displayed, which
  410. // means that, pShowingTexture is available as a decoding target.
  411. if ( pSubmittedTexture )
  412. {
  413. // If GetOverlayUpdateStatus() returns FALSE then we can still proceed and
  414. // call GetNextFrame(), but we will pass NULL for the surface parameter.
  415. // Some work will still be done, but none of the surfaces will be altered.
  416. if ( pDevice->GetOverlayUpdateStatus() )
  417. {
  418. // The call to UpdateOverlay() with pSubmittedTexture must have taken
  419. // effect now, so pShowingTexture is available as a decoding target.
  420. assert( !pDecodingTexture );
  421. pDecodingTexture = pShowingTexture;
  422. pShowingTexture = pSubmittedTexture;
  423. pSubmittedTexture = NULL;
  424. }
  425. }
  426. LPDIRECT3DSURFACE8 pSurface = NULL;
  427. if ( pDecodingTexture )
  428. pDecodingTexture->GetSurfaceLevel( 0, &pSurface );
  429. // Decode some information to the current draw texture, which may be NULL.
  430. // pDecodingTexture will be NULL if one texture has been submitted as a new
  431. // overlay but the other one is still being displayed as an overlay.
  432. // If pSurface is NULL GetNextFrame() will still do some work.
  433. XMVRESULT xr = XMV_NOFRAME;
  434. m_pXMVDecoder->GetNextFrame( pSurface, &xr, NULL );
  435. switch ( xr )
  436. {
  437. case XMV_NOFRAME:
  438. // Do nothing - we didn't get a frame.
  439. break;
  440. case XMV_NEWFRAME:
  441. ++m_dwCurrentFrame;
  442. // GetNextFrame produced a new frame. So, the texture we were decoding
  443. // to becomes available for displaying as an overlay.
  444. // The other texture is not ready to be a decoding target. It is still
  445. // being displayed as an overlay. So, we assign the newly decoded
  446. // texture to pSubmittedTexture for the program to submit as an overlay,
  447. // but we don't yet move the previously submitted texture from pShowing
  448. // to pDecoding. That happens on a subsequent call to this function, after
  449. // GetOverlayUpdateStatus() returns TRUE to tell us that there are no
  450. // overlay swaps pending.
  451. assert( pDecodingTexture );
  452. assert( !pSubmittedTexture );
  453. pSubmittedTexture = pDecodingTexture;
  454. pDecodingTexture = NULL;
  455. break;
  456. case XMV_ENDOFFILE:
  457. m_bPlaying = FALSE;
  458. break;
  459. case XMV_FAIL:
  460. // Data corruption or file read error. We'll treat that the same as
  461. // end of file.
  462. m_bPlaying = FALSE;
  463. m_bError = TRUE;
  464. break;
  465. }
  466. SAFE_RELEASE( pSurface );
  467. // If we just unpacked a new frame then we return that texture
  468. // and the program must call UpdateOverlay() with the surface
  469. // from that texture.
  470. // If we didn't unpack a frame then the program should do nothing -
  471. // the previous overlay will continue to be displayed.
  472. if ( XMV_NEWFRAME == xr )
  473. return pSubmittedTexture;
  474. // No new frame to display.
  475. return 0;
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Name: TerminatePlayback()
  479. // Desc: Calls XMVDecoder::TerminatePlayback()
  480. //-----------------------------------------------------------------------------
  481. void CXMVPlayer::TerminatePlayback()
  482. {
  483. m_pXMVDecoder->TerminatePlayback();
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Name: Play()
  487. // Desc: Calls XMVDecoder::Play() to play the entire movie.
  488. //-----------------------------------------------------------------------------
  489. HRESULT CXMVPlayer::Play( DWORD Flags, RECT* pRect )
  490. {
  491. // You have to call Open before calling Play.
  492. assert( m_pXMVDecoder );
  493. // Don't pass bAllocateTextures==TRUE to Open if you're going to use Play.
  494. assert( !m_pTextures[0] );
  495. return m_pXMVDecoder->Play( Flags, pRect );
  496. }
  497. //-----------------------------------------------------------------------------
  498. // Name: EnableOverlays()
  499. // Desc: Enable the overlay planes for playing the movie in them, and record
  500. // that the overlays should be disabled when Destroy() is called.
  501. //-----------------------------------------------------------------------------
  502. void CXMVPlayer::EnableOverlays( LPDIRECT3DDEVICE8 pDevice )
  503. {
  504. m_pDevice = pDevice;
  505. pDevice->EnableOverlay( TRUE );
  506. m_bOverlaysEnabled = TRUE;
  507. }
  508. //-----------------------------------------------------------------------------
  509. // Name: GetNextPacket()
  510. // Desc: Callback function to get next packet from a file
  511. //-----------------------------------------------------------------------------
  512. static HRESULT CALLBACK GetNextPacket( DWORD dwContext, VOID** ppPacket,
  513. DWORD* pOffsetToNextPacket )
  514. {
  515. LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext;
  516. if( NULL == pContext )
  517. return E_FAIL;
  518. // If the next packet is fully loaded then return it,
  519. // otherwise return NULL.
  520. DWORD dwBytesRead;
  521. if( GetOverlappedResult( pContext->hFile, &pContext->Overlapped,
  522. &dwBytesRead, FALSE ) )
  523. {
  524. // Make the old decoding packet pending.
  525. pContext->pPendingReleasePacket = pContext->pDecodingPacket;
  526. pContext->pDecodingPacket = pContext->pLoadingPacket;
  527. pContext->pLoadingPacket = NULL;
  528. // Offset to the next packet.
  529. *pOffsetToNextPacket = dwBytesRead;
  530. // Set *ppPacket to the data we just loaded.
  531. *ppPacket = pContext->pDecodingPacket;
  532. }
  533. else
  534. {
  535. DWORD dwError = GetLastError();
  536. // If we're waiting on the IO to finish, just do nothing.
  537. if( dwError != ERROR_IO_INCOMPLETE )
  538. return HRESULT_FROM_WIN32( dwError );
  539. *ppPacket = NULL;
  540. *pOffsetToNextPacket = 0;
  541. }
  542. return S_OK;
  543. }
  544. //-----------------------------------------------------------------------------
  545. // Name: ReleasePreviousPacket()
  546. // Desc: Callback function to release previous packet from a file
  547. //-----------------------------------------------------------------------------
  548. static HRESULT CALLBACK ReleasePreviousPacket( DWORD dwContext, LONGLONG llNextReadByteOffset,
  549. DWORD dwNextPacketSize )
  550. {
  551. LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext;
  552. if( NULL == pContext )
  553. return E_FAIL;
  554. if( dwNextPacketSize != 0 )
  555. {
  556. // Start the next load.
  557. pContext->Overlapped.Offset = ( DWORD )( llNextReadByteOffset & 0xFFFFFFFF );
  558. pContext->Overlapped.OffsetHigh = ( DWORD )( llNextReadByteOffset >> 32 );
  559. // Check for bad input file - buffer overrun
  560. if( dwNextPacketSize > pContext->dwPacketSize )
  561. return E_FAIL;
  562. pContext->pLoadingPacket = pContext->pPendingReleasePacket;
  563. pContext->pPendingReleasePacket = NULL;
  564. if( 0 == ReadFile( pContext->hFile, pContext->pLoadingPacket,
  565. dwNextPacketSize, NULL, &pContext->Overlapped ) )
  566. {
  567. if( GetLastError() != ERROR_IO_PENDING )
  568. return HRESULT_FROM_WIN32( GetLastError() );
  569. }
  570. }
  571. return S_OK;
  572. }
  573. //-----------------------------------------------------------------------------
  574. // Name: GetNextMemoryPacket()
  575. // Desc: Callback function to get next packet from a file,
  576. // and setup for the next packet.
  577. //-----------------------------------------------------------------------------
  578. static HRESULT CALLBACK GetNextMemoryPacket( DWORD dwContext, VOID** ppPacket,
  579. DWORD* pOffsetToNextPacket )
  580. {
  581. LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext;
  582. if( NULL == pContext )
  583. return E_FAIL;
  584. DWORD dwBytesRead = pContext->inputSize - pContext->readOffset;
  585. if ( pContext->currentPacketSize < dwBytesRead )
  586. dwBytesRead = pContext->currentPacketSize;
  587. memcpy( pContext->pLoadingPacket, pContext->pInputBuffer + pContext->readOffset , dwBytesRead );
  588. pContext->readOffset +=dwBytesRead;
  589. // Swap pointers so that next time we load it goes into the other packet block.
  590. BYTE* temp = pContext->pLoadingPacket;
  591. pContext->pLoadingPacket = pContext->pDecodingPacket;
  592. pContext->pDecodingPacket = temp;
  593. // Offset to the next packet.
  594. *pOffsetToNextPacket = dwBytesRead;
  595. // Set *ppPacket to the data we just loaded.
  596. *ppPacket = pContext->pDecodingPacket;
  597. return S_OK;
  598. }
  599. //-----------------------------------------------------------------------------
  600. // Name: ReleasePreviousMemoryPacket()
  601. // Desc: Callback function to release previous packet from a block of memory,
  602. // and setup for the next packet.
  603. //-----------------------------------------------------------------------------
  604. static HRESULT CALLBACK ReleasePreviousMemoryPacket( DWORD dwContext, LONGLONG llNextReadByteOffset,
  605. DWORD dwNextPacketSize )
  606. {
  607. LOAD_CONTEXT* pContext = ( LOAD_CONTEXT* )dwContext;
  608. if( NULL == pContext )
  609. return E_FAIL;
  610. // Check for bad input file - buffer overrun
  611. if( dwNextPacketSize > pContext->dwPacketSize )
  612. return E_FAIL;
  613. // Record the size of the next packet we are supposed to read, for GetNextMemoryPacket.
  614. pContext->currentPacketSize = dwNextPacketSize;
  615. return S_OK;
  616. }