Subversion Repositories spk

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
11 cycrow 1
#include "Movies.h"
2
#include <dshow.h>
3
#include <windows.h>
4
#include <mmsystem.h>
5
#include <atlbase.h>
6
 
7
//#define NO_AUDIO_RENDERER
8
 
9
LPDIRECT3DTEXTURE9 m_pTexture = NULL; // our texture
10
 
11
CComPtr<IGraphBuilder>  g_pGB;          // GraphBuilder
12
CComPtr<IMediaControl>  g_pMC;          // Media Control
13
CComPtr<IMediaPosition> g_pMP;          // Media Position
14
CComPtr<IMediaEvent>    g_pME;          // Media Event
15
CComPtr<IBaseFilter>    g_pRenderer;    // our custom renderer
16
 
17
D3DFORMAT               g_TextureFormat; // Texture format
18
 
19
 
20
LPDIRECT3DDEVICE9 gD3dDevice2;
21
 
22
//////////
23
// Construction/Destruction
24
//
25
 
26
CMovies::CMovies()
27
{
28
	Clean();
29
}
30
 
31
LPDIRECT3DTEXTURE9 CMovies::GetTexture () { return m_pTexture; }
32
 
33
CMovies::~CMovies()
34
{
35
	CoUninitialize();
36
}
37
 
38
bool CMovies::Initialise( LPDIRECT3DDEVICE9 device, const char *szVideoFilename, LPDIRECT3DTEXTURE9 texture )
39
{
40
	if ( m_cVideoFilename == szVideoFilename )
41
	{
42
		Stop();
43
		return true;
44
	}
45
 
46
	Clean();
47
 
48
	m_cVideoFilename = (char*)szVideoFilename; 
49
 
50
	gD3dDevice2 = device;
51
 
52
	//CoInitialize(NULL);
53
 
54
	HRESULT hr = S_OK;
55
	CComPtr<IBaseFilter>    pFSrc;			// Source Filter
56
	CComPtr<IPin>           pFSrcPinOut;	// Source Filter Output Pin   
57
	CTextureRenderer        *pCTR = 0;		// DirectShow Texture renderer
58
 
59
//	Create the filter graph
60
	if ( FAILED( g_pGB.CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC) ) )
61
		return false;
62
 
63
//	Create the Texture Renderer object
64
	pCTR = new CTextureRenderer(NULL, &hr);
65
 
66
    if ( FAILED(hr) || !pCTR )
67
		return false;
68
 
69
	g_pRenderer = pCTR;
70
//	pFTR = pCTR;
71
 
72
	if ( FAILED( g_pGB->AddFilter(g_pRenderer, L"TEXTURERENDERER") ) )
73
		return false;
74
 
75
	TCHAR strFileName[MAX_PATH];
76
	WCHAR wFileName[MAX_PATH];
77
 
78
	lstrcpyn( strFileName, szVideoFilename, MAX_PATH - 1 );
79
 
80
    strFileName[MAX_PATH-1] = 0;
81
    wFileName[MAX_PATH-1] = 0;
82
 
83
	USES_CONVERSION;
84
	wcsncpy(wFileName, T2W(strFileName), NUMELMS(wFileName));
85
 
86
	hr = g_pGB->AddSourceFilter (wFileName, L"SOURCE", &pFSrc);
87
 
88
//	If the media file was not found, inform the user.
89
	if ( hr == VFW_E_NOT_FOUND )
90
	{
91
//		Msg(TEXT("Could not add source filter to graph!  (hr==VFW_E_NOT_FOUND)\r\n\r\n")
92
//			TEXT("This sample reads a media file from the DirectX SDK's media path.\r\n")
93
//			TEXT("Please install the DirectX 9 SDK on this machine."));
94
		return false;
95
	}
96
	else if ( FAILED( hr ) )
97
	{
98
//		Msg(TEXT("Could not add source filter to graph!  hr=0x%x"), hr);
99
		return false;
100
	}
101
 
102
	if ( FAILED( pFSrc->FindPin(L"Output", &pFSrcPinOut) ) )
103
	{
104
//		Msg(TEXT("Could not find output pin!  hr=0x%x"), hr);
105
		return false;
106
	}
107
 
108
#ifdef NO_AUDIO_RENDERER
109
 
110
	CComPtr<IPin> pFTRPinIn;      // Texture Renderer Input Pin
111
 
112
//	Find the source's output pin and the renderer's input pin
113
	if ( FAILED( g_pRenderer->FindPin(L"In", &pFTRPinIn) ) )
114
	{
115
//		Msg(TEXT("Could not find input pin!  hr=0x%x"), hr);
116
		return false;
117
	}
118
 
119
//	Connect these two filters
120
	if ( FAILED( g_pGB->Connect(pFSrcPinOut, pFTRPinIn) ) )
121
	{
122
//		Msg(TEXT("Could not connect pins!  hr=0x%x"), hr);
123
		return false;
124
	}
125
 
126
#else
127
 
128
	// Render the source filter's output pin.  The Filter Graph Manager
129
	// will connect the video stream to the loaded CTextureRenderer
130
	// and will load and connect an audio renderer (if needed).
131
 
132
	if ( FAILED( g_pGB->Render(pFSrcPinOut) ) )
133
	{
134
//		Msg(TEXT("Could not render source output pin!  hr=0x%x"), hr);
135
		return false;
136
	}
137
 
138
#endif
139
 
140
//	Get the graph's media control, event & position interfaces
141
	g_pGB.QueryInterface(&g_pMC);
142
	g_pGB.QueryInterface(&g_pMP);
143
	g_pGB.QueryInterface(&g_pME);
144
 
145
	m_iVideoWidth = pCTR->m_lVidWidth;
146
	m_iVideoHeight = pCTR->m_lVidHeight;
147
	m_fRotation = 0.0f;
148
 
149
	return true;
150
}
151
 
152
void CMovies::Clean()
153
{
154
	g_pGB = NULL;
155
	g_pMP = NULL;
156
	g_pMC = NULL;
157
	g_pME = NULL;
158
	g_pRenderer = NULL;
159
 
160
	m_cVideoFilename = NULL;
161
	m_bPlaying = false;
162
	m_bPaused = true;
163
}
164
 
165
bool CMovies::Play()
166
{
167
	if ( FAILED( g_pMC->Run() ) )
168
		return false;
169
 
170
	m_bPlaying = true;
171
	m_bPaused = false;
172
 
173
	return true;
174
}
175
 
176
bool CMovies::Stop()
177
{
178
	if ( FAILED ( g_pMC->Stop() ) )
179
		return false;
180
 
181
	double temp;
182
 
183
	g_pMP->get_CurrentPosition( &temp );
184
 
185
	if ( FAILED ( g_pMP->put_CurrentPosition( 0 ) ) )
186
		return false;
187
 
188
//	temp += 0;
189
 
190
	m_bPlaying = false;
191
	m_bPaused = true;
192
 
193
	return true;
194
}
195
 
196
bool CMovies::Pause()
197
{
198
	if ( FAILED ( g_pMC->Pause() ) )
199
		return false;
200
 
201
	m_bPaused = true;
202
 
203
	return true;
204
}
205
 
206
bool CMovies::JumpTo( double PositionInSeconds )
207
{
208
	if ( FAILED ( g_pMP->put_CurrentPosition( PositionInSeconds ) ) )
209
		return false;
210
 
211
	return true;
212
}
213
 
214
bool CMovies::HasMovieEnded()
215
{
216
	long lEventCode, lParam1, lParam2;
217
 
218
//	Check for completion events
219
	HRESULT hr = g_pME->GetEvent(&lEventCode, (LONG_PTR *) &lParam1, (LONG_PTR *) &lParam2, 0);
220
 
221
	if (SUCCEEDED(hr))
222
	{
223
		if ( EC_COMPLETE == lEventCode ) 
224
			return true;
225
 
226
//		Free any memory associated with this event
227
		hr = g_pME->FreeEventParams(lEventCode, lParam1, lParam2);
228
	}
229
 
230
	return false;
231
}
232
 
233
long CMovies::MovieLength()
234
{
235
	double length;
236
 
237
	g_pMP->get_Duration( &length );
238
 
239
	return (long)length * 1000;
240
}
241
 
242
//////////
243
//	Construction / Deconstruction
244
//
245
CTextureRenderer::CTextureRenderer( LPUNKNOWN pUnk, HRESULT *phr )
246
                                  : CBaseVideoRenderer(__uuidof(CLSID_TextureRenderer), 
247
                                    NAME("Texture Renderer"), pUnk, phr),
248
                                    m_bUseDynamicTextures(FALSE)
249
{
250
//	Store and AddRef the texture for our use.
251
	if (phr)
252
		*phr = S_OK;
253
}
254
 
255
 
256
CTextureRenderer::~CTextureRenderer()
257
{
258
 
259
}
260
 
261
HRESULT CTextureRenderer::CheckMediaType(const CMediaType *pmt)
262
{
263
 
264
    HRESULT   hr = E_FAIL;
265
    VIDEOINFO *pvi=0;
266
 
267
    CheckPointer(pmt,E_POINTER);
268
 
269
    // Reject the connection if this is not a video type
270
    if( *pmt->FormatType() != FORMAT_VideoInfo ) {
271
        return E_INVALIDARG;
272
    }
273
 
274
// Only accept RGB24 video
275
    pvi = (VIDEOINFO *)pmt->Format();
276
 
277
    if ( IsEqualGUID( *pmt->Type(),    MEDIATYPE_Video )  &&
278
		 IsEqualGUID( *pmt->Subtype(), MEDIASUBTYPE_RGB24 ) )
279
		hr = S_OK;
280
    return hr;
281
  }
282
 
283
HRESULT CTextureRenderer::SetMediaType(const CMediaType *pmt)
284
{
285
    HRESULT hr;
286
 
287
    UINT uintWidth = 2;
288
    UINT uintHeight = 2;
289
 
290
    // Retrive the size of this media type
291
    D3DCAPS9 caps;
292
    VIDEOINFO *pviBmp;                      // Bitmap info header
293
    pviBmp = (VIDEOINFO *)pmt->Format();
294
 
295
    m_lVidWidth  = pviBmp->bmiHeader.biWidth;
296
    m_lVidHeight = abs(pviBmp->bmiHeader.biHeight);
297
    m_lVidPitch  = (m_lVidWidth * 3 + 3) & ~(3); // We are forcing RGB24
298
 
299
    // here let's check if we can use dynamic textures
300
    ZeroMemory( &caps, sizeof(D3DCAPS9));
301
 
302
    hr = gD3dDevice2->GetDeviceCaps( &caps );
303
/*
304
    if ( caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES )
305
    {
306
        m_bUseDynamicTextures = true;
307
    }*/
308
 
309
    if( caps.TextureCaps & D3DPTEXTURECAPS_POW2 )
310
    {
311
        while( (LONG)uintWidth < m_lVidWidth )
312
            uintWidth = uintWidth << 1;
313
 
314
		while( (LONG)uintHeight < m_lVidHeight )
315
            uintHeight = uintHeight << 1;
316
    }
317
    else
318
    {
319
        uintWidth = m_lVidWidth;
320
        uintHeight = m_lVidHeight;
321
    }
322
 
323
 
324
//	Create the texture that maps to this media type
325
    hr = E_UNEXPECTED;
326
 
327
    if( m_bUseDynamicTextures )
328
    {
329
        hr = gD3dDevice2->CreateTexture( uintWidth, uintHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8,D3DPOOL_DEFAULT,
330
										&m_pTexture, NULL );
331
        if( FAILED(hr))
332
            m_bUseDynamicTextures = FALSE;
333
    }
334
 
335
    if( FALSE == m_bUseDynamicTextures )
336
        hr = gD3dDevice2->CreateTexture(uintWidth, uintHeight, 1, 0, 
337
                                         D3DFMT_X8R8G8B8,D3DPOOL_MANAGED,
338
                                         &m_pTexture, NULL);
339
 
340
	if ( FAILED(hr) )
341
		return false;
342
 
343
    // CreateTexture can silently change the parameters on us
344
    D3DSURFACE_DESC ddsd;
345
    ZeroMemory(&ddsd, sizeof(ddsd));
346
 
347
    if ( FAILED( m_pTexture->GetLevelDesc( 0, &ddsd ) ) ) 
348
        return false;
349
 
350
    CComPtr<IDirect3DSurface9> pSurf; 
351
 
352
    if ( SUCCEEDED( hr = m_pTexture->GetSurfaceLevel(0, &pSurf) ) )
353
        pSurf->GetDesc(&ddsd);
354
 
355
    // Save format info
356
    g_TextureFormat = ddsd.Format;
357
 
358
    if ( (g_TextureFormat != D3DFMT_X8R8G8B8) && (g_TextureFormat != D3DFMT_A1R5G5B5) )
359
        return VFW_E_TYPE_NOT_ACCEPTED;
360
 
361
    return S_OK;
362
}
363
 
364
HRESULT CTextureRenderer::DoRenderSample( IMediaSample * pSample )
365
{
366
 
367
    BYTE  *pBmpBuffer, *pTxtBuffer; // Bitmap buffer, texture buffer
368
    LONG  lTxtPitch;                // Pitch of bitmap, texture
369
 
370
    BYTE  * pbS = NULL;
371
    DWORD * pdwS = NULL;
372
    DWORD * pdwD = NULL;
373
    UINT row, col, dwordWidth, backwards;
374
 
375
    CheckPointer( pSample,E_POINTER );
376
    CheckPointer( m_pTexture,E_UNEXPECTED );
377
 
378
    // Get the video bitmap buffer
379
    pSample->GetPointer( &pBmpBuffer );
380
 
381
    // Lock the Texture
382
    D3DLOCKED_RECT d3dlr;
383
    if( m_bUseDynamicTextures )
384
    {
385
        if( FAILED(m_pTexture->LockRect(0, &d3dlr, 0, D3DLOCK_DISCARD)))
386
            return E_FAIL;
387
    }
388
    else
389
    {
390
        if (FAILED(m_pTexture->LockRect(0, &d3dlr, 0, 0)))
391
            return E_FAIL;
392
    }
393
    // Get the texture buffer & pitch
394
    pTxtBuffer = static_cast<byte *>(d3dlr.pBits);
395
    lTxtPitch = d3dlr.Pitch;
396
 
397
//	Copy the bits    
398
    if ( g_TextureFormat == D3DFMT_X8R8G8B8 )
399
    {
400
        // Instead of copying data bytewise, we use DWORD alignment here.
401
        // We also unroll loop by copying 4 pixels at once.
402
        //
403
        // original BYTE array is [b0][g0][r0][b1][g1][r1][b2][g2][r2][b3][g3][r3]
404
        //
405
        // aligned DWORD array is     [b1 r0 g0 b0][g2 b2 r1 g1][r3 g3 b3 r2]
406
        //
407
        // We want to transform it to [ff r0 g0 b0][ff r1 g1 b1][ff r2 g2 b2][ff r3 b3 g3]
408
        // below, bitwise operations do exactly this.
409
 
410
        dwordWidth = m_lVidWidth / 4; // aligned width of the row, in DWORDS
411
                                      // (pixel by 3 bytes over sizeof(DWORD))
412
 
413
		backwards = m_lVidWidth * m_lVidHeight * 4;
414
 
415
        for( row = 0; row< (UINT)m_lVidHeight; row++)
416
        {
417
            pdwS = ( DWORD* )pBmpBuffer;
418
            pdwD = ( DWORD* )pTxtBuffer;
419
 
420
			for( col = 0; col < dwordWidth; col ++ )
421
			{
422
				pdwD[0] =  pdwS[0] | 0xFF000000;
423
				pdwD[1] = ( ( pdwS[1] << 8)  | 0xFF000000) | ( pdwS[0] >> 24 );
424
				pdwD[2] = ( ( pdwS[2] << 16) | 0xFF000000) | ( pdwS[1] >> 16 );
425
				pdwD[3] = 0xFF000000 | ( pdwS[2] >> 8 );
426
				pdwD += 4; 
427
				pdwS += 3;
428
			}
429
 
430
 
431
//			We might have remaining (misaligned) bytes here
432
            pbS = (BYTE*) pdwS;
433
            for( col = 0; col < (UINT)m_lVidWidth % 4; col++)
434
            {
435
                *pdwD = 0xFF000000     |
436
                        (pbS[2] << 16) |
437
                        (pbS[1] <<  8) |
438
                        (pbS[0]);
439
                pdwD++;
440
                pbS += 3;           
441
            }
442
 
443
            pBmpBuffer  += m_lVidPitch;
444
            pTxtBuffer += lTxtPitch;
445
        }// for rows
446
    }
447
 
448
    if (g_TextureFormat == D3DFMT_A1R5G5B5) 
449
    {
450
        for(int y = 0; y < m_lVidHeight; y++ ) 
451
        {
452
            BYTE *pBmpBufferOld = pBmpBuffer;
453
            BYTE *pTxtBufferOld = pTxtBuffer;   
454
 
455
            for (int x = 0; x < m_lVidWidth; x++) 
456
            {
457
                *(WORD *)pTxtBuffer = (WORD)
458
                    (0x8000 +
459
                    ((pBmpBuffer[2] & 0xF8) << 7) +
460
                    ((pBmpBuffer[1] & 0xF8) << 2) +
461
                    (pBmpBuffer[0] >> 3));
462
 
463
                pTxtBuffer += 2;
464
                pBmpBuffer += 3;
465
            }
466
 
467
            pBmpBuffer = pBmpBufferOld + m_lVidPitch;
468
            pTxtBuffer = pTxtBufferOld + lTxtPitch;
469
        }
470
    }
471
 
472
    // Unlock the Texture
473
    if ( FAILED( m_pTexture->UnlockRect(0) ) )
474
        return E_FAIL;
475
 
476
    return S_OK;
477
}
478
 
479
 
480