Blame | Last modification | View Log | RSS feed
#include "Movies.h"#include <dshow.h>#include <windows.h>#include <mmsystem.h>#include <atlbase.h>//#define NO_AUDIO_RENDERERLPDIRECT3DTEXTURE9 m_pTexture = NULL; // our textureCComPtr<IGraphBuilder> g_pGB; // GraphBuilderCComPtr<IMediaControl> g_pMC; // Media ControlCComPtr<IMediaPosition> g_pMP; // Media PositionCComPtr<IMediaEvent> g_pME; // Media EventCComPtr<IBaseFilter> g_pRenderer; // our custom rendererD3DFORMAT g_TextureFormat; // Texture formatLPDIRECT3DDEVICE9 gD3dDevice2;//////////// Construction/Destruction//CMovies::CMovies(){Clean();}LPDIRECT3DTEXTURE9 CMovies::GetTexture () { return m_pTexture; }CMovies::~CMovies(){CoUninitialize();}bool CMovies::Initialise( LPDIRECT3DDEVICE9 device, const char *szVideoFilename, LPDIRECT3DTEXTURE9 texture ){if ( m_cVideoFilename == szVideoFilename ){Stop();return true;}Clean();m_cVideoFilename = (char*)szVideoFilename;gD3dDevice2 = device;//CoInitialize(NULL);HRESULT hr = S_OK;CComPtr<IBaseFilter> pFSrc; // Source FilterCComPtr<IPin> pFSrcPinOut; // Source Filter Output PinCTextureRenderer *pCTR = 0; // DirectShow Texture renderer// Create the filter graphif ( FAILED( g_pGB.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC) ) )return false;// Create the Texture Renderer objectpCTR = new CTextureRenderer(NULL, &hr);if ( FAILED(hr) || !pCTR )return false;g_pRenderer = pCTR;// pFTR = pCTR;if ( FAILED( g_pGB->AddFilter(g_pRenderer, L"TEXTURERENDERER") ) )return false;TCHAR strFileName[MAX_PATH];WCHAR wFileName[MAX_PATH];lstrcpyn( strFileName, szVideoFilename, MAX_PATH - 1 );strFileName[MAX_PATH-1] = 0;wFileName[MAX_PATH-1] = 0;USES_CONVERSION;wcsncpy(wFileName, T2W(strFileName), NUMELMS(wFileName));hr = g_pGB->AddSourceFilter (wFileName, L"SOURCE", &pFSrc);// If the media file was not found, inform the user.if ( hr == VFW_E_NOT_FOUND ){// Msg(TEXT("Could not add source filter to graph! (hr==VFW_E_NOT_FOUND)\r\n\r\n")// TEXT("This sample reads a media file from the DirectX SDK's media path.\r\n")// TEXT("Please install the DirectX 9 SDK on this machine."));return false;}else if ( FAILED( hr ) ){// Msg(TEXT("Could not add source filter to graph! hr=0x%x"), hr);return false;}if ( FAILED( pFSrc->FindPin(L"Output", &pFSrcPinOut) ) ){// Msg(TEXT("Could not find output pin! hr=0x%x"), hr);return false;}#ifdef NO_AUDIO_RENDERERCComPtr<IPin> pFTRPinIn; // Texture Renderer Input Pin// Find the source's output pin and the renderer's input pinif ( FAILED( g_pRenderer->FindPin(L"In", &pFTRPinIn) ) ){// Msg(TEXT("Could not find input pin! hr=0x%x"), hr);return false;}// Connect these two filtersif ( FAILED( g_pGB->Connect(pFSrcPinOut, pFTRPinIn) ) ){// Msg(TEXT("Could not connect pins! hr=0x%x"), hr);return false;}#else// Render the source filter's output pin. The Filter Graph Manager// will connect the video stream to the loaded CTextureRenderer// and will load and connect an audio renderer (if needed).if ( FAILED( g_pGB->Render(pFSrcPinOut) ) ){// Msg(TEXT("Could not render source output pin! hr=0x%x"), hr);return false;}#endif// Get the graph's media control, event & position interfacesg_pGB.QueryInterface(&g_pMC);g_pGB.QueryInterface(&g_pMP);g_pGB.QueryInterface(&g_pME);m_iVideoWidth = pCTR->m_lVidWidth;m_iVideoHeight = pCTR->m_lVidHeight;m_fRotation = 0.0f;return true;}void CMovies::Clean(){g_pGB = NULL;g_pMP = NULL;g_pMC = NULL;g_pME = NULL;g_pRenderer = NULL;m_cVideoFilename = NULL;m_bPlaying = false;m_bPaused = true;}bool CMovies::Play(){if ( FAILED( g_pMC->Run() ) )return false;m_bPlaying = true;m_bPaused = false;return true;}bool CMovies::Stop(){if ( FAILED ( g_pMC->Stop() ) )return false;double temp;g_pMP->get_CurrentPosition( &temp );if ( FAILED ( g_pMP->put_CurrentPosition( 0 ) ) )return false;// temp += 0;m_bPlaying = false;m_bPaused = true;return true;}bool CMovies::Pause(){if ( FAILED ( g_pMC->Pause() ) )return false;m_bPaused = true;return true;}bool CMovies::JumpTo( double PositionInSeconds ){if ( FAILED ( g_pMP->put_CurrentPosition( PositionInSeconds ) ) )return false;return true;}bool CMovies::HasMovieEnded(){long lEventCode, lParam1, lParam2;// Check for completion eventsHRESULT hr = g_pME->GetEvent(&lEventCode, (LONG_PTR *) &lParam1, (LONG_PTR *) &lParam2, 0);if (SUCCEEDED(hr)){if ( EC_COMPLETE == lEventCode )return true;// Free any memory associated with this eventhr = g_pME->FreeEventParams(lEventCode, lParam1, lParam2);}return false;}long CMovies::MovieLength(){double length;g_pMP->get_Duration( &length );return (long)length * 1000;}//////////// Construction / Deconstruction//CTextureRenderer::CTextureRenderer( LPUNKNOWN pUnk, HRESULT *phr ): CBaseVideoRenderer(__uuidof(CLSID_TextureRenderer),NAME("Texture Renderer"), pUnk, phr),m_bUseDynamicTextures(FALSE){// Store and AddRef the texture for our use.if (phr)*phr = S_OK;}CTextureRenderer::~CTextureRenderer(){}HRESULT CTextureRenderer::CheckMediaType(const CMediaType *pmt){HRESULT hr = E_FAIL;VIDEOINFO *pvi=0;CheckPointer(pmt,E_POINTER);// Reject the connection if this is not a video typeif( *pmt->FormatType() != FORMAT_VideoInfo ) {return E_INVALIDARG;}// Only accept RGB24 videopvi = (VIDEOINFO *)pmt->Format();if ( IsEqualGUID( *pmt->Type(), MEDIATYPE_Video ) &&IsEqualGUID( *pmt->Subtype(), MEDIASUBTYPE_RGB24 ) )hr = S_OK;return hr;}HRESULT CTextureRenderer::SetMediaType(const CMediaType *pmt){HRESULT hr;UINT uintWidth = 2;UINT uintHeight = 2;// Retrive the size of this media typeD3DCAPS9 caps;VIDEOINFO *pviBmp; // Bitmap info headerpviBmp = (VIDEOINFO *)pmt->Format();m_lVidWidth = pviBmp->bmiHeader.biWidth;m_lVidHeight = abs(pviBmp->bmiHeader.biHeight);m_lVidPitch = (m_lVidWidth * 3 + 3) & ~(3); // We are forcing RGB24// here let's check if we can use dynamic texturesZeroMemory( &caps, sizeof(D3DCAPS9));hr = gD3dDevice2->GetDeviceCaps( &caps );/*if ( caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES ){m_bUseDynamicTextures = true;}*/if( caps.TextureCaps & D3DPTEXTURECAPS_POW2 ){while( (LONG)uintWidth < m_lVidWidth )uintWidth = uintWidth << 1;while( (LONG)uintHeight < m_lVidHeight )uintHeight = uintHeight << 1;}else{uintWidth = m_lVidWidth;uintHeight = m_lVidHeight;}// Create the texture that maps to this media typehr = E_UNEXPECTED;if( m_bUseDynamicTextures ){hr = gD3dDevice2->CreateTexture( uintWidth, uintHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8,D3DPOOL_DEFAULT,&m_pTexture, NULL );if( FAILED(hr))m_bUseDynamicTextures = FALSE;}if( FALSE == m_bUseDynamicTextures )hr = gD3dDevice2->CreateTexture(uintWidth, uintHeight, 1, 0,D3DFMT_X8R8G8B8,D3DPOOL_MANAGED,&m_pTexture, NULL);if ( FAILED(hr) )return false;// CreateTexture can silently change the parameters on usD3DSURFACE_DESC ddsd;ZeroMemory(&ddsd, sizeof(ddsd));if ( FAILED( m_pTexture->GetLevelDesc( 0, &ddsd ) ) )return false;CComPtr<IDirect3DSurface9> pSurf;if ( SUCCEEDED( hr = m_pTexture->GetSurfaceLevel(0, &pSurf) ) )pSurf->GetDesc(&ddsd);// Save format infog_TextureFormat = ddsd.Format;if ( (g_TextureFormat != D3DFMT_X8R8G8B8) && (g_TextureFormat != D3DFMT_A1R5G5B5) )return VFW_E_TYPE_NOT_ACCEPTED;return S_OK;}HRESULT CTextureRenderer::DoRenderSample( IMediaSample * pSample ){BYTE *pBmpBuffer, *pTxtBuffer; // Bitmap buffer, texture bufferLONG lTxtPitch; // Pitch of bitmap, textureBYTE * pbS = NULL;DWORD * pdwS = NULL;DWORD * pdwD = NULL;UINT row, col, dwordWidth, backwards;CheckPointer( pSample,E_POINTER );CheckPointer( m_pTexture,E_UNEXPECTED );// Get the video bitmap bufferpSample->GetPointer( &pBmpBuffer );// Lock the TextureD3DLOCKED_RECT d3dlr;if( m_bUseDynamicTextures ){if( FAILED(m_pTexture->LockRect(0, &d3dlr, 0, D3DLOCK_DISCARD)))return E_FAIL;}else{if (FAILED(m_pTexture->LockRect(0, &d3dlr, 0, 0)))return E_FAIL;}// Get the texture buffer & pitchpTxtBuffer = static_cast<byte *>(d3dlr.pBits);lTxtPitch = d3dlr.Pitch;// Copy the bitsif ( g_TextureFormat == D3DFMT_X8R8G8B8 ){// Instead of copying data bytewise, we use DWORD alignment here.// We also unroll loop by copying 4 pixels at once.//// original BYTE array is [b0][g0][r0][b1][g1][r1][b2][g2][r2][b3][g3][r3]//// aligned DWORD array is [b1 r0 g0 b0][g2 b2 r1 g1][r3 g3 b3 r2]//// We want to transform it to [ff r0 g0 b0][ff r1 g1 b1][ff r2 g2 b2][ff r3 b3 g3]// below, bitwise operations do exactly this.dwordWidth = m_lVidWidth / 4; // aligned width of the row, in DWORDS// (pixel by 3 bytes over sizeof(DWORD))backwards = m_lVidWidth * m_lVidHeight * 4;for( row = 0; row< (UINT)m_lVidHeight; row++){pdwS = ( DWORD* )pBmpBuffer;pdwD = ( DWORD* )pTxtBuffer;for( col = 0; col < dwordWidth; col ++ ){pdwD[0] = pdwS[0] | 0xFF000000;pdwD[1] = ( ( pdwS[1] << 8) | 0xFF000000) | ( pdwS[0] >> 24 );pdwD[2] = ( ( pdwS[2] << 16) | 0xFF000000) | ( pdwS[1] >> 16 );pdwD[3] = 0xFF000000 | ( pdwS[2] >> 8 );pdwD += 4;pdwS += 3;}// We might have remaining (misaligned) bytes herepbS = (BYTE*) pdwS;for( col = 0; col < (UINT)m_lVidWidth % 4; col++){*pdwD = 0xFF000000 |(pbS[2] << 16) |(pbS[1] << 8) |(pbS[0]);pdwD++;pbS += 3;}pBmpBuffer += m_lVidPitch;pTxtBuffer += lTxtPitch;}// for rows}if (g_TextureFormat == D3DFMT_A1R5G5B5){for(int y = 0; y < m_lVidHeight; y++ ){BYTE *pBmpBufferOld = pBmpBuffer;BYTE *pTxtBufferOld = pTxtBuffer;for (int x = 0; x < m_lVidWidth; x++){*(WORD *)pTxtBuffer = (WORD)(0x8000 +((pBmpBuffer[2] & 0xF8) << 7) +((pBmpBuffer[1] & 0xF8) << 2) +(pBmpBuffer[0] >> 3));pTxtBuffer += 2;pBmpBuffer += 3;}pBmpBuffer = pBmpBufferOld + m_lVidPitch;pTxtBuffer = pTxtBufferOld + lTxtPitch;}}// Unlock the Textureif ( FAILED( m_pTexture->UnlockRect(0) ) )return E_FAIL;return S_OK;}