framework2

Форк
0
1352 строки · 39.3 Кб
1
#include "ofDirectShowPlayer.h"
2
#include "ofPixels.h"
3
#include "ofMath.h"
4

5
#ifdef _MSC_VER
6
#pragma comment(lib,"Strmiids.lib")
7
#endif
8

9
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
10
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
11
// DirectShow includes and helper methods 
12
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
13
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
14

15

16
#include <dshow.h>
17
#ifdef _MSC_VER
18
#pragma include_alias( "dxtrans.h", "qedit.h" )
19
#endif
20
#define __IDxtCompositor_INTERFACE_DEFINED__
21
#define __IDxtAlphaSetter_INTERFACE_DEFINED__
22
#define __IDxtJpeg_INTERFACE_DEFINED__
23
#define __IDxtKey_INTERFACE_DEFINED__
24
#include <aviriff.h>
25
#include <windows.h>
26

27
//for threading
28
#include <process.h>
29

30
// Due to a missing qedit.h in recent Platform SDKs, we've replicated the relevant contents here
31
// #include <qedit.h>
32
MIDL_INTERFACE("0579154A-2B53-4994-B0D0-E773148EFF85")
33
ISampleGrabberCB : public IUnknown
34
{
35
  public:
36
    virtual HRESULT STDMETHODCALLTYPE SampleCB( 
37
        double SampleTime,
38
        IMediaSample *pSample) = 0;
39
    
40
    virtual HRESULT STDMETHODCALLTYPE BufferCB( 
41
        double SampleTime,
42
        BYTE *pBuffer,
43
        long BufferLen) = 0;
44
    
45
};
46

47
MIDL_INTERFACE("6B652FFF-11FE-4fce-92AD-0266B5D7C78F")
48
ISampleGrabber : public IUnknown
49
{
50
  public:
51
    virtual HRESULT STDMETHODCALLTYPE SetOneShot( 
52
        BOOL OneShot) = 0;
53
    
54
    virtual HRESULT STDMETHODCALLTYPE SetMediaType( 
55
        const AM_MEDIA_TYPE *pType) = 0;
56
    
57
    virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType( 
58
        AM_MEDIA_TYPE *pType) = 0;
59
    
60
    virtual HRESULT STDMETHODCALLTYPE SetBufferSamples( 
61
        BOOL BufferThem) = 0;
62
    
63
    virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer( 
64
        /* [out][in] */ long *pBufferSize,
65
        /* [out] */ long *pBuffer) = 0;
66
    
67
    virtual HRESULT STDMETHODCALLTYPE GetCurrentSample( 
68
        /* [retval][out] */ IMediaSample **ppSample) = 0;
69
    
70
    virtual HRESULT STDMETHODCALLTYPE SetCallback( 
71
        ISampleGrabberCB *pCallback,
72
        long WhichMethodToCallback) = 0;
73
    
74
};
75
EXTERN_C const CLSID CLSID_SampleGrabber;
76
EXTERN_C const IID IID_ISampleGrabber;
77
EXTERN_C const CLSID CLSID_NullRenderer;
78

79
// GetUnconnectedPin   
80
//    Finds an unconnected pin on a filter in the desired direction   
81
HRESULT GetUnconnectedPin(   
82
                          IBaseFilter *pFilter,   // Pointer to the filter.   
83
                          PIN_DIRECTION PinDir,   // Direction of the pin to find.   
84
                          IPin **ppPin)           // Receives a pointer to the pin.   
85
{   
86
    *ppPin = 0;   
87
    IEnumPins *pEnum = 0;   
88
    IPin *pPin = 0;   
89
    HRESULT hr = pFilter->EnumPins(&pEnum);   
90
    if (FAILED(hr))   
91
    {   
92
        return hr;   
93
    }   
94
    while (pEnum->Next(1, &pPin, NULL) == S_OK)   
95
    {   
96
        PIN_DIRECTION ThisPinDir;   
97
        pPin->QueryDirection(&ThisPinDir);   
98
        if (ThisPinDir == PinDir)   
99
        {   
100
            IPin *pTmp = 0;   
101
            hr = pPin->ConnectedTo(&pTmp);   
102
            if (SUCCEEDED(hr))  // Already connected, not the pin we want.   
103
            {   
104
                pTmp->Release();   
105
            }   
106
            else  // Unconnected, this is the pin we want.   
107
            {   
108
                pEnum->Release();   
109
                *ppPin = pPin;   
110
                return S_OK;   
111
            }   
112
        }   
113
        pPin->Release();   
114
    }   
115
    pEnum->Release();   
116
    // Did not find a matching pin.   
117
    return E_FAIL;   
118
}   
119
 
120
// Disconnect any connections to the filter.   
121
HRESULT DisconnectPins(IBaseFilter *pFilter)   
122
{   
123
    IEnumPins *pEnum = 0;   
124
    IPin *pPin = 0;   
125
    HRESULT hr = pFilter->EnumPins(&pEnum);   
126
    if (FAILED(hr))   
127
    {   
128
        return hr;   
129
    }   
130
 
131
    while (pEnum->Next(1, &pPin, NULL) == S_OK)   
132
    {   
133
        pPin->Disconnect();   
134
        pPin->Release();   
135
    }   
136
    pEnum->Release();   
137
 
138
    // Did not find a matching pin.   
139
    return S_OK;   
140
}   
141
 
142
// ConnectFilters   
143
//    Connects a pin of an upstream filter to the pDest downstream filter   
144
HRESULT ConnectFilters(   
145
                       IGraphBuilder *pGraph, // Filter Graph Manager.   
146
                       IPin *pOut,            // Output pin on the upstream filter.   
147
                       IBaseFilter *pDest)    // Downstream filter.   
148
{   
149
    if ((pGraph == NULL) || (pOut == NULL) || (pDest == NULL))   
150
    {   
151
        return E_POINTER;   
152
    }   
153
#ifdef debug   
154
    PIN_DIRECTION PinDir;   
155
    pOut->QueryDirection(&PinDir);   
156
    _ASSERTE(PinDir == PINDIR_OUTPUT);   
157
#endif   
158
 
159
    // Find an input pin on the downstream filter.   
160
    IPin *pIn = 0;   
161
    HRESULT hr = GetUnconnectedPin(pDest, PINDIR_INPUT, &pIn);   
162
    if (FAILED(hr))   
163
    {   
164
        return hr;   
165
    }   
166
    // Try to connect them.   
167
    hr = pGraph->Connect(pOut, pIn);   
168
    pIn->Release();   
169
    return hr;   
170
}   
171
 
172
 
173
 
174
// ConnectFilters   
175
//    Connects two filters   
176
HRESULT ConnectFilters(   
177
                       IGraphBuilder *pGraph,    
178
                       IBaseFilter *pSrc,    
179
                       IBaseFilter *pDest)   
180
{   
181
    if ((pGraph == NULL) || (pSrc == NULL) || (pDest == NULL))   
182
    {   
183
        return E_POINTER;   
184
    }   
185
 
186
    // Find an output pin on the first filter.   
187
    IPin *pOut = 0;   
188
    HRESULT hr = GetUnconnectedPin(pSrc, PINDIR_OUTPUT, &pOut);   
189
    if (FAILED(hr))    
190
    {   
191
        return hr;   
192
    }   
193
    hr = ConnectFilters(pGraph, pOut, pDest);   
194
    pOut->Release();   
195
    return hr;   
196
}   
197
 
198
// LocalFreeMediaType   
199
//    Free the format buffer in the media type   
200
void LocalFreeMediaType(AM_MEDIA_TYPE& mt)   
201
{   
202
    if (mt.cbFormat != 0)   
203
    {   
204
        CoTaskMemFree((PVOID)mt.pbFormat);   
205
        mt.cbFormat = 0;   
206
        mt.pbFormat = NULL;   
207
    }   
208
    if (mt.pUnk != NULL)   
209
    {   
210
        // Unecessary because pUnk should not be used, but safest.   
211
        mt.pUnk->Release();   
212
        mt.pUnk = NULL;   
213
    }   
214
}   
215
 
216
// LocalDeleteMediaType   
217
//    Free the format buffer in the media type,    
218
//    then delete the MediaType ptr itself   
219
void LocalDeleteMediaType(AM_MEDIA_TYPE *pmt)   
220
{   
221
    if (pmt != NULL)   
222
    {   
223
        LocalFreeMediaType(*pmt); // See FreeMediaType for the implementation.   
224
        CoTaskMemFree(pmt);   
225
    }   
226
}
227

228

229
HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath) 
230
{
231
    const WCHAR wszStreamName[] = L"ActiveMovieGraph"; 
232
    HRESULT hr;
233
    
234
    IStorage *pStorage = NULL;
235
    hr = StgCreateDocfile(
236
        wszPath,
237
        STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
238
        0, &pStorage);
239
    if(FAILED(hr)) 
240
    {
241
        return hr;
242
    }
243

244
    IStream *pStream;
245
    hr = pStorage->CreateStream(
246
        wszStreamName,
247
        STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
248
        0, 0, &pStream);
249
    if (FAILED(hr)) 
250
    {
251
        pStorage->Release();    
252
        return hr;
253
    }
254

255
    IPersistStream *pPersist = NULL;
256
    pGraph->QueryInterface(IID_IPersistStream, (void**)&pPersist);
257
    hr = pPersist->Save(pStream, TRUE);
258
    pStream->Release();
259
    pPersist->Release();
260
    if (SUCCEEDED(hr)) 
261
    {
262
        hr = pStorage->Commit(STGC_DEFAULT);
263
    }
264
    pStorage->Release();
265
    return hr;
266
}
267

268
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
269
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
270
// DirectShowVideo - contains a simple directshow video player implementation
271
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
272
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
273

274
namespace{
275
    int comRefCount = 0;
276

277
    void retainCom(){
278
        if( comRefCount == 0 ){
279
            //printf("com is initialized!\n");
280
            CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
281
        }
282
        comRefCount++;
283
    }
284

285
    void releaseCom(){
286
        comRefCount--;
287
        if( comRefCount == 0 ){
288
            //printf("com is uninitialized!\n");
289
            CoUninitialize();
290
        }
291
    }
292

293
    void releaseSample(IMediaSample * sample){
294
        sample->Release();
295
    }
296
}
297

298

299
class DirectShowVideo : public ISampleGrabberCB{
300
    public:
301

302
    DirectShowVideo(){
303
        retainCom();
304
        clearValues();
305
        InitializeCriticalSection(&critSection);
306
    }
307

308
    ~DirectShowVideo(){
309
        tearDown();
310
		middleSample.reset();
311
		backSample.reset();
312
        releaseCom(); 
313
        DeleteCriticalSection(&critSection);
314
    }
315

316
    void tearDown(){
317
        //printf("tearDown\n"); 
318

319
        if(m_pControl){
320
            m_pControl->Release();
321
        }
322
        if(m_pEvent){
323
            m_pEvent->Release();
324
        }
325
        if(m_pSeek){
326
            m_pSeek->Release();
327
        }
328
        if(m_pAudio){
329
            m_pAudio->Release();
330
        }
331
        if(m_pBasicVideo){
332
            m_pBasicVideo->Release();
333
        }
334
        if(m_pGrabber){
335
            m_pGrabber->Release();
336
        }
337
        if(m_pGrabberF){
338
            m_pGrabberF->Release();
339
        }
340
        if(m_pGraph){
341
            m_pGraph->Release();
342
        }
343
        if(m_pNullRenderer){
344
            m_pNullRenderer->Release();
345
        }
346
        if( m_pSourceFile ){
347
            m_pSourceFile->Release();
348
        }
349
        if( m_pPosition ){
350
            m_pPosition->Release();
351
        }
352
        clearValues(); 
353
    }
354

355
    void clearValues(){
356
        hr = 0;
357

358
        m_pGraph = NULL;
359
        m_pControl = NULL; 
360
        m_pEvent = NULL; 
361
        m_pSeek = NULL; 
362
        m_pAudio = NULL; 
363
        m_pGrabber = NULL;
364
        m_pGrabberF = NULL;
365
        m_pBasicVideo = NULL;
366
        m_pNullRenderer = NULL;
367
        m_pSourceFile = NULL;
368
        m_pPosition = NULL;
369

370
        timeNow = 0; 
371
        lPositionInSecs = 0; 
372
        lDurationInNanoSecs = 0; 
373
        lTotalDuration = 0; 
374
        rtNew = 0; 
375
        lPosition = 0; 
376
        lvolume = -1000;
377
        evCode = 0; 
378
        width = height = 0; 
379
        bVideoOpened = false;    
380
        bLoop = true;
381
        bPaused = false;
382
        bPlaying = false;
383
        bEndReached = false; 
384
        bNewPixels = false;
385
        bFrameNew = false;
386
        curMovieFrame = -1; 
387
        frameCount = -1;
388

389
        movieRate = 1.0; 
390
        averageTimePerFrame = 1.0/30.0;
391
    }
392

393
    //------------------------------------------------
394
    STDMETHODIMP_(ULONG) AddRef() { return 1; }
395
    STDMETHODIMP_(ULONG) Release() { return 2; }
396

397

398
    //------------------------------------------------
399
    STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject){
400
        *ppvObject = static_cast<ISampleGrabberCB*>(this);
401
        return S_OK;
402
    }
403

404

405
    //------------------------------------------------
406
    STDMETHODIMP SampleCB(double Time, IMediaSample *pSample){
407

408
        BYTE * ptrBuffer = NULL; 
409
        HRESULT hr = pSample->GetPointer(&ptrBuffer);
410

411
        if(hr == S_OK){
412
            std::size_t latestBufferLength = pSample->GetActualDataLength();
413
            if(latestBufferLength == pixels.getTotalBytes() ){
414
                EnterCriticalSection(&critSection);
415
				pSample->AddRef();
416
                backSample = std::unique_ptr<IMediaSample, std::function<void(IMediaSample*)>>(pSample, releaseSample);
417
                bNewPixels = true;
418

419
                //this is just so we know if there is a new frame
420
                frameCount++;
421

422
                LeaveCriticalSection(&critSection);
423
            }else{
424
                ofLogError() << "SampleCB() - buffer sizes do not match "<< latestBufferLength << " " << pixels.getTotalBytes();
425
            }
426
        }
427

428
        return S_OK;
429
    }
430

431
    //This method is meant to have more overhead
432
    STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen){
433
        return E_NOTIMPL;
434
    }
435

436
    bool loadMovie(of::filesystem::path path, ofPixelFormat format){
437
        tearDown();
438
		this->pixelFormat = format;
439

440
    // Create the Filter Graph Manager and query for interfaces.
441

442
        //printf("step 1\n"); 
443
        hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void **)&m_pGraph);
444
        if (FAILED(hr)){
445
            tearDown(); 
446
            return false;
447
        }
448

449
        //printf("step 2\n"); 
450
        hr = m_pGraph->QueryInterface(IID_IMediaSeeking, (void**)&m_pSeek);
451
        if (FAILED(hr)){
452
            tearDown(); 
453
            return false;
454
        }
455

456
        hr = m_pGraph->QueryInterface(IID_IMediaPosition, (LPVOID *)&m_pPosition);
457
        if (FAILED(hr)){
458
            tearDown(); 
459
            return false;
460
        }
461

462
        hr = m_pGraph->QueryInterface(IID_IBasicAudio,(void**)&m_pAudio);
463
        if (FAILED(hr)){
464
            tearDown(); 
465
            return false;
466
        }
467

468
        // Use IGraphBuilder::QueryInterface (inherited from IUnknown) to get the IMediaControl interface.
469
        //printf("step 4\n"); 
470
        hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pControl);
471
        if (FAILED(hr)){
472
            tearDown(); 
473
            return false;
474
        }  
475
    
476
        // And get the Media Event interface, too.
477
        //printf("step 5\n"); 
478
        hr = m_pGraph->QueryInterface(IID_IMediaEvent, (void **)&m_pEvent);
479
        if (FAILED(hr)){
480
            tearDown(); 
481
            return false;
482
        } 
483

484
        //SAMPLE GRABBER (ALLOWS US TO GRAB THE BUFFER)//
485
        // Create the Sample Grabber.
486
        hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)&m_pGrabberF);
487
        if (FAILED(hr)){
488
            tearDown(); 
489
            return false;
490
        } 
491

492
        hr = m_pGraph->AddFilter(m_pGrabberF, L"Sample Grabber");
493
        if (FAILED(hr)){
494
            tearDown(); 
495
            return false;
496
        }
497

498
        hr = m_pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&m_pGrabber);
499
        if (FAILED(hr)){
500
            tearDown(); 
501
            return false;
502
        }
503

504
        hr = m_pGrabber->SetCallback(this, 0);
505
        if (FAILED(hr)){
506
            tearDown(); 
507
            return false;
508
        }
509

510
        //MEDIA CONVERSION
511
        //Get video properties from the stream's mediatype and apply to the grabber (otherwise we don't get an RGB image)
512
        AM_MEDIA_TYPE mt;
513
        ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));
514

515
        mt.majortype    = MEDIATYPE_Video;
516
		switch (format) {
517
		case OF_PIXELS_RGB:
518
		case OF_PIXELS_BGR:
519
			mt.subtype = MEDIASUBTYPE_RGB24;
520
			break;
521
		case OF_PIXELS_BGRA:
522
		case OF_PIXELS_RGBA:
523
			mt.subtype = MEDIASUBTYPE_RGB32;
524
			break;
525
		default:
526
			ofLogError("DirectShowPlayer") << "Trying to set unsupported format this is an internal bug, using default RGB";
527
			mt.subtype = MEDIASUBTYPE_RGB24;
528
		}
529

530
        mt.formattype   = FORMAT_VideoInfo;
531
        //printf("step 5.5\n"); 
532
        hr = m_pGrabber->SetMediaType(&mt);
533
        if (FAILED(hr)){
534
            tearDown(); 
535
            return false;
536
        }
537

538
        //printf("step 6\n"); 
539
        std::string pathString = path.string();
540
        std::wstring filePathW = std::wstring(pathString.begin(), pathString.end());
541

542
        //this is the easier way to connect the graph, but we have to remove the video window manually
543
        hr = m_pGraph->RenderFile(filePathW.c_str(), NULL);
544

545
        //this is the more manual way to do it - its a pain though because the audio won't be connected by default
546
        /*hr = m_pGraph->AddSourceFilter(filePathW.c_str(), L"Source", &m_pSourceFile); 
547
        if (FAILED(hr)){
548
            printf("unable to AddSourceFilter\n");
549
            tearDown(); 
550
            return false;
551
        }*/
552
        //hr = ConnectFilters(m_pGraph, m_pSourceFile, m_pGrabberF);
553
        //if (FAILED(hr)){
554
        //  printf("unable to ConnectFilters(m_pGraph, m_pSourceFile, m_pGrabberF)\n");
555
        //  tearDown(); 
556
        //  return false;
557
        //}
558

559
        //printf("step 7\n"); 
560
        if (SUCCEEDED(hr)){
561

562
            //Set Params - One Shot should be false unless you want to capture just one buffer
563
            hr = m_pGrabber->SetOneShot(FALSE);
564
            if (FAILED(hr)){
565
                printf("unable to set one shot\n");
566
                tearDown(); 
567
                return false;
568
            }
569
            
570
            //apparently setting to TRUE causes a small memory leak
571
            hr = m_pGrabber->SetBufferSamples(FALSE);
572
            if (FAILED(hr)){
573
                printf("unable to set buffer samples\n");
574
                tearDown(); 
575
                return false;
576
            }
577

578
            //NULL RENDERER//
579
            //used to give the video stream somewhere to go to.
580
            hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)(&m_pNullRenderer));
581
            if (FAILED(hr)){
582
                printf("null renderer error\n");
583
                tearDown(); 
584
                return false;
585
            }       
586

587
            hr = m_pGraph->AddFilter(m_pNullRenderer, L"Render");
588
            if (FAILED(hr)){
589
                printf("unable to add null renderer\n");
590
                tearDown(); 
591
                return false;
592
            }
593
            
594
            //hr = ConnectFilters(m_pGraph, m_pGrabberF, m_pNullRenderer);
595
            //if (FAILED(hr)){
596
            //  printf("unable to ConnectFilters(m_pGraph, m_pGrabberF, m_pNullRenderer)\n");
597
            //  tearDown(); 
598
            //  return false;
599
            //}
600
    
601
            AM_MEDIA_TYPE mt;
602
            ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));
603
			
604
            hr = m_pGrabber->GetConnectedMediaType(&mt);
605
            if (FAILED(hr)){
606
                printf("unable to call GetConnectedMediaType\n");
607
                tearDown(); 
608
                return false;
609
            }
610

611
            VIDEOINFOHEADER * infoheader = (VIDEOINFOHEADER*)mt.pbFormat;
612
            width = infoheader->bmiHeader.biWidth;
613
            height = infoheader->bmiHeader.biHeight;
614
            averageTimePerFrame = infoheader->AvgTimePerFrame / 10000000.0;
615
			pixels.allocate(width, height, pixelFormat);
616

617
            //printf("video dimensions are %i %i\n", width, height); 
618

619
            //we need to manually change the output from the renderer window to the null renderer
620
            IBaseFilter * m_pVideoRenderer;
621
            IPin* pinIn = 0;
622
            IPin* pinOut = 0;
623

624
            hr = m_pGraph->FindFilterByName(L"Video Renderer", &m_pVideoRenderer);
625

626
			if (FAILED(hr)) {
627
				//newer graphs use Video Mixing Renderer 9
628
				hr = m_pGraph->FindFilterByName(L"Video Mixing Renderer 9", &m_pVideoRenderer);
629
				if (FAILED(hr)) {
630
					printf("failed to find the video renderer\n");
631
					tearDown();
632
					return false;
633
				}
634
			}
635

636
            //we disconnect the video renderer window by finding the output pin of the sample grabber
637
            hr = m_pGrabberF->FindPin(L"Out", &pinOut);
638
            if (FAILED(hr)){
639
                printf("failed to find the sample grabber output pin\n");
640
                tearDown();
641
                return false;
642
            }
643

644
            hr = pinOut->Disconnect();
645
            if (FAILED(hr)){
646
                printf("failed to disconnect grabber output pin\n");
647
                tearDown();
648
                return false;
649
            }
650

651
            //SaveGraphFile(m_pGraph, L"test1.grf");
652

653
            //we have to remove it as well otherwise the graph builder will reconnect it
654
            hr = m_pGraph->RemoveFilter(m_pVideoRenderer);
655
            if (FAILED(hr)){            
656
                printf("failed to remove the default renderer\n");
657
                tearDown();
658
                return false;
659
            }else{
660
                m_pVideoRenderer->Release();
661
            }
662

663
            //now connect the null renderer to the grabber output, if we don't do this not frames will be captured
664
            hr = m_pNullRenderer->FindPin(L"In", &pinIn);
665
            if (FAILED(hr)){            
666
                printf("failed to find the input pin of the null renderer\n");
667
                tearDown();
668
                return false;
669
            }
670

671
            hr = pinOut->Connect(pinIn, NULL);
672
            if (FAILED(hr)){            
673
                printf("failed to connect the null renderer\n");
674
                tearDown();
675
                return false;
676
            }
677

678
            //printf("step 8\n"); 
679
            // Run the graph.
680
        
681
            //SaveGraphFile(m_pGraph, L"test2.grf");
682
            hr = m_pControl->Run(); 
683
            //SaveGraphFile(m_pGraph, L"test3.grf");
684

685
            // Now pause the graph.
686
            hr = m_pControl->Stop();
687
            updatePlayState();
688

689
            if( FAILED(hr) || width == 0 || height == 0 ){
690
                tearDown();
691
                printf("Error occured while playing or pausing or opening the file\n");
692
                return false; 
693
            }
694
        }else{
695
            tearDown();
696
            printf("Error occured while playing or pausing or opening the file\n");
697
            return false; 
698
        }
699

700
        bVideoOpened = true;
701
        return true; 
702
    }
703

704
    void update(){
705
        if( bVideoOpened ){
706

707
            long eventCode = 0;
708
#ifdef _WIN64
709
            long long ptrParam1 = 0;
710
            long long ptrParam2 = 0;
711
#else
712
            long ptrParam1 = 0;
713
            long ptrParam2 = 0;
714
#endif
715
            if( curMovieFrame != frameCount ){
716
                bFrameNew = true;
717
            }else{
718
                bFrameNew = false; 
719
            }
720
            curMovieFrame = frameCount;
721

722
            while (S_OK == m_pEvent->GetEvent(&eventCode, &ptrParam1, &ptrParam2, 0)){
723
                if (eventCode == EC_COMPLETE ){
724
                    if(bLoop){
725
                        //printf("Restarting!\n");
726
                        setPosition(0.0);
727
                    }else{
728
                        bEndReached = true; 
729
                        //printf("movie end reached!\n");
730
                        stop();
731
                        updatePlayState(); 
732
                    }
733
                }
734
                //printf("Event code: %#04x\n Params: %d, %d\n", eventCode, ptrParam1, ptrParam2);
735
                m_pEvent->FreeEventParams(eventCode, ptrParam1, ptrParam2);
736
            }
737
        }
738
    }
739

740
    bool isLoaded(){
741
        return bVideoOpened;
742
    }
743

744
    //volume has to be log corrected/converted
745
    void setVolume(float volPct){
746
        if( isLoaded() ){   
747
            if( volPct < 0 ) volPct = 0.0;
748
            if( volPct > 1 ) volPct = 1.0; 
749

750
            long vol = log10(volPct) * 4000.0;
751
            if(vol < -8000){
752
                vol = -10000;
753
            }
754
            m_pAudio->put_Volume(vol);
755
        }
756
    }
757

758
    float getVolume(){
759
        float volPct = 0.0;
760
        if( isLoaded() ){
761
            long vol = 0;
762
            m_pAudio->get_Volume(&vol);
763
            volPct = powf(10, (float)vol/4000.0);
764
        }
765
        return volPct;
766
    }
767

768
    double getDurationInSeconds(){
769
        if( isLoaded() ){
770
            long long lDurationInNanoSecs = 0;
771
            m_pSeek->GetDuration(&lDurationInNanoSecs);
772
            double timeInSeconds = (double)lDurationInNanoSecs/10000000.0;
773

774
            return timeInSeconds;
775
        }
776
        return 0.0;
777
    }
778

779
    double getCurrentTimeInSeconds(){
780
        if( isLoaded() ){
781
            long long lCurrentTimeInNanoSecs = 0;
782
            m_pSeek->GetCurrentPosition(&lCurrentTimeInNanoSecs);
783
            double timeInSeconds = (double)lCurrentTimeInNanoSecs/10000000.0;
784

785
            return timeInSeconds;
786
        }
787
        return 0.0;
788
    }
789

790
    void setPosition(float pct){
791
        if( bVideoOpened ){
792
            if( pct < 0.0 ) pct = 0.0; 
793
            if( pct > 1.0 ) pct = 1.0; 
794
            
795
            long long lDurationInNanoSecs = 0;
796
            m_pSeek->GetDuration(&lDurationInNanoSecs);
797

798
            rtNew = ((float)lDurationInNanoSecs * pct);             
799
            hr = m_pSeek->SetPositions(&rtNew, AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);
800
        }
801
    }
802

803
    float getPosition(){
804
        if( bVideoOpened ){
805
            float timeDur = getDurationInSeconds(); 
806
            if( timeDur > 0.0 ){
807
                return getCurrentTimeInSeconds() / timeDur; 
808
            }
809
        }
810
        return 0.0; 
811
    }
812

813
    void setSpeed(float speed){
814
        if( bVideoOpened ){
815
            m_pPosition->put_Rate(speed);
816
            m_pPosition->get_Rate(&movieRate);
817
        }
818
    }
819

820
    double getSpeed(){
821
        return movieRate;
822
    }
823

824
	bool needsRBSwap(ofPixelFormat srcFormat, ofPixelFormat dstFormat) {
825
		return
826
			((srcFormat == OF_PIXELS_BGR || srcFormat == OF_PIXELS_BGRA) && (dstFormat == OF_PIXELS_RGB || dstFormat == OF_PIXELS_RGBA)) ||
827
			((srcFormat == OF_PIXELS_RGB || srcFormat == OF_PIXELS_RGBA) && (dstFormat == OF_PIXELS_BGR || dstFormat == OF_PIXELS_BGRA));
828
	}
829

830
    void processPixels(ofPixels & src, ofPixels & dst){
831
		auto format = src.getPixelFormat();
832

833
        if(needsRBSwap(format, dst.getPixelFormat())){
834
			if (format == OF_PIXELS_BGR) {
835
				dst.allocate(src.getWidth(), src.getHeight(), OF_PIXELS_RGB);
836
				auto dstLine = dst.getLines().begin();
837
				auto srcLine = --src.getLines().end();
838
				auto endLine = dst.getLines().end();
839
				for (; dstLine != endLine; dstLine++, srcLine--) {
840
					auto dstPixel = dstLine.getPixels().begin();
841
					auto srcPixel = srcLine.getPixels().begin();
842
					auto endPixel = dstLine.getPixels().end();
843
					for (; dstPixel != endPixel; dstPixel++, srcPixel++) {
844
						dstPixel[0] = srcPixel[2];
845
						dstPixel[1] = srcPixel[1];
846
						dstPixel[2] = srcPixel[0];
847
					}
848
				}
849
			}
850
			else if (format == OF_PIXELS_BGRA) {
851
				dst.allocate(src.getWidth(), src.getHeight(), OF_PIXELS_RGBA);
852
				auto dstLine = dst.getLines().begin();
853
				auto srcLine = --src.getLines().end();
854
				auto endLine = dst.getLines().end();
855
				for (; dstLine != endLine; dstLine++, srcLine--) {
856
					auto dstPixel = dstLine.getPixels().begin();
857
					auto srcPixel = srcLine.getPixels().begin();
858
					auto endPixel = dstLine.getPixels().end();
859
					for (; dstPixel != endPixel; dstPixel++, srcPixel++) {
860
						dstPixel[0] = srcPixel[2];
861
						dstPixel[1] = srcPixel[1];
862
						dstPixel[2] = srcPixel[0];
863
					}
864
				}
865
			}
866
		} else {
867
			src.mirrorTo(dst, true, false);
868
		}
869
    }
870

871
    void play(){
872
        if( bVideoOpened ){
873
            m_pControl->Run(); 
874
            bEndReached = false; 
875
            updatePlayState();
876
        }
877
    }
878

879
    void stop(){
880
        if( bVideoOpened ){
881
            if( isPlaying() ){
882
                setPosition(0.0); 
883
            }
884
            m_pControl->Stop();
885
            updatePlayState();
886
        }
887
    }
888

889
    void setPaused(bool bPaused){
890
        if( bVideoOpened ){
891
            if( bPaused ){
892
                m_pControl->Pause(); 
893
            }else{
894
                m_pControl->Run(); 
895
            }
896
            updatePlayState();
897
        }
898
        
899
    }
900

901
    void updatePlayState(){
902
        if( bVideoOpened ){
903
            FILTER_STATE fs;
904
            hr = m_pControl->GetState(4000, (OAFilterState*)&fs);
905
            if(hr==S_OK){
906
                if( fs == State_Running ){
907
                    bPlaying = true; 
908
                    bPaused = false;
909
                }
910
                else if( fs == State_Paused ){
911
                    bPlaying = false;
912
                    bPaused = true;
913
                }else if( fs == State_Stopped ){
914
                    bPlaying = false;
915
                    bPaused = false;
916
                }
917
            }
918
        }
919
    }
920

921
    bool isPlaying(){
922
        return bPlaying;
923
    }
924

925
    bool isPaused(){
926
        return bPaused;
927
    }
928

929
    bool isLooping(){
930
        return bLoop; 
931
    }
932

933
    void setLoop(bool loop){
934
        bLoop = loop; 
935
    }
936

937
    bool isMovieDone(){
938
        return bEndReached;
939
    }
940

941
    float getWidth(){
942
        return width;
943
    }
944

945
    float getHeight(){
946
        return height;
947
    }
948

949
    bool isFrameNew(){
950
        return bFrameNew;
951
    }
952

953
    void nextFrame(){
954
        //we have to do it like this as the frame based approach is not very accurate
955
        if( bVideoOpened && ( isPlaying() || isPaused() ) ){
956
            int curFrame = getCurrentFrameNo();
957
            float curFrameF = curFrame; 
958
            for(int i = 1; i < 20; i++){
959
                setAproximateFrameF( curFrameF + 0.3 * (float)i );  
960
                if( getCurrentFrameNo() >= curFrame + 1 ){
961
                    break;
962
                }
963
            }
964
        }
965
    }
966

967
    void preFrame(){
968
        //we have to do it like this as the frame based approach is not very accurate
969
        if( bVideoOpened && ( isPlaying() || isPaused() ) ){
970
            int curFrame = getCurrentFrameNo();
971
            float curFrameF = curFrame; 
972
            for(int i = 1; i < 20; i++){
973
                setAproximateFrameF( curFrameF - 0.3 * (float)i );  
974
                if( getCurrentFrameNo() <= curFrame + 1 ){
975
                    break;
976
                }
977
            }
978
        }
979
    }
980

981
    void setAproximateFrameF(float frameF){
982
        if( bVideoOpened ){
983
            float pct = frameF / (float)getAproximateNoFrames();
984
            if( pct > 1.0 ) pct = 1.0; 
985
            if( pct < 0.0 ) pct = 0.0; 
986
            setPosition(pct); 
987
        }
988
    }
989

990
    void setAproximateFrame(int frame){
991
        if( bVideoOpened ){
992
            float pct = (float)frame / (float)getAproximateNoFrames();
993
            if( pct > 1.0 ) pct = 1.0; 
994
            if( pct < 0.0 ) pct = 0.0; 
995
            setPosition(pct); 
996
        }
997
    }
998

999
    int getCurrentFrameNo(){
1000
        if( bVideoOpened ){
1001
            return getPosition() * (float) getAproximateNoFrames(); 
1002
        }
1003
        return 0; 
1004
    }
1005

1006
    int getAproximateNoFrames(){
1007
        if( bVideoOpened && averageTimePerFrame > 0.0 ){
1008
            return getDurationInSeconds() / averageTimePerFrame; 
1009
        }
1010
        return 0;
1011
    }
1012

1013
    ofPixels & getPixels(){
1014
        if(bVideoOpened && bNewPixels){
1015
            EnterCriticalSection(&critSection);
1016
			std::swap(backSample, middleSample);
1017
			bNewPixels = false;
1018
			LeaveCriticalSection(&critSection);
1019
			BYTE * ptrBuffer = NULL;
1020
			if( middleSample->GetPointer(&ptrBuffer) == S_OK) {
1021
                ofPixels srcBuffer;
1022
                switch (pixelFormat) {
1023
                case OF_PIXELS_RGB:
1024
                case OF_PIXELS_BGR:
1025
                    srcBuffer.setFromExternalPixels(ptrBuffer, width, height, OF_PIXELS_BGR);
1026
                    break;
1027
                case OF_PIXELS_RGBA:
1028
                case OF_PIXELS_BGRA:
1029
                    srcBuffer.setFromExternalPixels(ptrBuffer, width, height, OF_PIXELS_BGRA);
1030
                    break;
1031
                case OF_PIXELS_GRAY:
1032
                case OF_PIXELS_GRAY_ALPHA:
1033
                case OF_PIXELS_RGB565:
1034
                case OF_PIXELS_NV12:
1035
                case OF_PIXELS_NV21:
1036
                case OF_PIXELS_YV12:
1037
                case OF_PIXELS_I420:
1038
                case OF_PIXELS_YUY2:
1039
                case OF_PIXELS_UYVY:
1040
                case OF_PIXELS_Y:
1041
                case OF_PIXELS_U:
1042
                case OF_PIXELS_V:
1043
                case OF_PIXELS_UV:
1044
                case OF_PIXELS_VU:
1045
                case OF_PIXELS_NUM_FORMATS:
1046
                case OF_PIXELS_UNKNOWN:
1047
                case OF_PIXELS_NATIVE:
1048
                default:
1049
                    break;
1050
                }
1051

1052
                processPixels(srcBuffer, pixels);
1053
            }
1054
        }
1055
		return pixels;
1056
    }
1057

1058
    //this is the non-callback approach
1059
    //void getPixels(unsigned char * dstBuffer){
1060
    //      
1061
    //  if(bVideoOpened && isFrameNew()){
1062
    //      long bufferSize = videoSize; 
1063
    //      HRESULT hr = m_pGrabber->GetCurrentBuffer(&bufferSize, (long *)rawBuffer);
1064
    //      
1065
    //      if(hr==S_OK){
1066
    //          if (videoSize == bufferSize){
1067
    //              processPixels(rawBuffer, dstBuffer, width, height, true, true);
1068
    //          }else{
1069
    //              printf("ERROR: GetPixels() - bufferSizes do not match!\n");
1070
    //          }
1071
    //      }else{
1072
    //          printf("ERROR: GetPixels() - Unable to get pixels for device  bufferSize = %i \n", bufferSize);
1073
    //      }
1074
    //  }
1075
    //}
1076

1077
    protected:
1078

1079
    HRESULT hr;                         // COM return value
1080
    IGraphBuilder *m_pGraph;        // Graph Builder interface
1081
    IMediaControl *m_pControl;  // Media Control interface
1082
    IMediaEvent   *m_pEvent;        // Media Event interface
1083
    IMediaSeeking *m_pSeek;     // Media Seeking interface
1084
    IMediaPosition * m_pPosition; 
1085
    IBasicAudio   *m_pAudio;        // Audio Settings interface 
1086
    ISampleGrabber * m_pGrabber;
1087
    IBaseFilter * m_pSourceFile;
1088
    IBaseFilter * m_pGrabberF; 
1089
    IBasicVideo * m_pBasicVideo;
1090
    IBaseFilter * m_pNullRenderer;
1091

1092
    REFERENCE_TIME timeNow;             // Used for FF & REW of movie, current time
1093
    LONGLONG lPositionInSecs;       // Time in  seconds
1094
    LONGLONG lDurationInNanoSecs;       // Duration in nanoseconds
1095
    LONGLONG lTotalDuration;        // Total duration
1096
    REFERENCE_TIME rtNew;               // Reference time of movie 
1097
    long lPosition;                 // Desired position of movie used in FF & REW
1098
    long lvolume;                   // The volume level in 1/100ths dB Valid values range from -10,000 (silence) to 0 (full volume), 0 = 0 dB -10000 = -100 dB 
1099
    long evCode;                    // event variable, used to in file to complete wait.
1100

1101
    long width, height;
1102

1103
    double averageTimePerFrame; 
1104

1105
    bool bFrameNew;
1106
    bool bNewPixels;
1107
    bool bVideoOpened;
1108
    bool bPlaying; 
1109
    bool bPaused;
1110
    bool bLoop; 
1111
    bool bEndReached;
1112
    double movieRate;
1113
    int curMovieFrame;
1114
    int frameCount;
1115

1116
    CRITICAL_SECTION critSection;
1117
	std::unique_ptr<IMediaSample, std::function<void(IMediaSample*)>> backSample;
1118
	std::unique_ptr<IMediaSample, std::function<void(IMediaSample*)>> middleSample;
1119
	ofPixels pixels;
1120
	ofPixelFormat pixelFormat;
1121
};
1122

1123

1124

1125

1126
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
1127
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
1128
// OF SPECIFIC IMPLEMENTATION BELOW 
1129
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
1130
//----------------------------------------------------------------------------------------------------------------------------------------------------------------
1131

1132
ofDirectShowPlayer::ofDirectShowPlayer()
1133
:pixelFormat(OF_PIXELS_RGB){
1134

1135
}
1136

1137
ofDirectShowPlayer::ofDirectShowPlayer(ofDirectShowPlayer && other)
1138
:player(std::move(other.player))
1139
,pixelFormat(std::move(other.pixelFormat)){
1140

1141
}
1142

1143
ofDirectShowPlayer & ofDirectShowPlayer::operator=(ofDirectShowPlayer&& other) {
1144
	if (&other == this) {
1145
		return *this;
1146
	}
1147

1148
	player = std::move(other.player);
1149
	pixelFormat = std::move(other.pixelFormat); 
1150
	return *this;
1151
}
1152

1153
// FIXME: convert to filesystem::path in near future
1154
bool ofDirectShowPlayer::load(std::string stringPath){
1155
    auto path = ofToDataPath(of::filesystem::path(stringPath));
1156

1157
    close();
1158
    player.reset(new DirectShowVideo());
1159
    bool loadOk = player->loadMovie(path, pixelFormat);
1160
    if( !loadOk ){
1161
        ofLogError("ofDirectShowPlayer") << " Cannot load video of this file type.  Make sure you have codecs installed on your system.  OF recommends the free K-Lite Codec pack. ";
1162
    }
1163
    return loadOk;
1164
}
1165

1166
void ofDirectShowPlayer::close(){
1167
	player.reset();
1168
}
1169

1170
void ofDirectShowPlayer::update(){
1171
    if( player && player->isLoaded() ){
1172
        player->update();
1173
    }
1174
}
1175

1176
void ofDirectShowPlayer::play(){
1177
    if( player && player->isLoaded() ){
1178
        player->play();
1179
    }
1180
}
1181

1182
void ofDirectShowPlayer::stop(){
1183
    if( player && player->isLoaded() ){
1184
        player->stop();
1185
    }
1186
}       
1187
    
1188
bool ofDirectShowPlayer::isFrameNew() const{
1189
    return ( player && player->isFrameNew() ); 
1190
}
1191

1192
const ofPixels & ofDirectShowPlayer::getPixels() const{
1193
    return player->getPixels();
1194
}
1195

1196
ofPixels & ofDirectShowPlayer::getPixels(){
1197
    return player->getPixels();
1198
}
1199

1200
float ofDirectShowPlayer::getWidth() const{
1201
    if( player && player->isLoaded() ){
1202
        return player->getWidth();
1203
    }
1204
    return 0.0; 
1205
}
1206

1207
float ofDirectShowPlayer::getHeight() const{
1208
    if( player && player->isLoaded() ){
1209
        return player->getHeight();
1210
    }
1211
    return 0.0;
1212
}
1213
    
1214
bool ofDirectShowPlayer::isPaused() const{
1215
    return ( player && player->isPaused() ); 
1216
}
1217

1218
bool ofDirectShowPlayer::isLoaded() const{
1219
    return ( player && player->isLoaded() ); 
1220
}
1221

1222
bool ofDirectShowPlayer::isPlaying() const{
1223
    return ( player && player->isPlaying() ); 
1224
}   
1225

1226
bool ofDirectShowPlayer::setPixelFormat(ofPixelFormat pixelFormat){
1227
	switch (pixelFormat) {
1228
	case OF_PIXELS_RGB:
1229
	case OF_PIXELS_BGR:
1230
	case OF_PIXELS_BGRA:
1231
	case OF_PIXELS_RGBA:
1232
		this->pixelFormat = pixelFormat;
1233
		return true;
1234
	default:
1235
		return false;
1236
	}
1237
}
1238

1239
ofPixelFormat ofDirectShowPlayer::getPixelFormat() const{
1240
    return this->pixelFormat; 
1241
}
1242
        
1243
//should implement!
1244
float ofDirectShowPlayer::getPosition() const{
1245
    if( player && player->isLoaded() ){
1246
        return player->getPosition();
1247
    }
1248
    return 0.0;
1249
}
1250

1251
float ofDirectShowPlayer::getSpeed() const{
1252
    if( player && player->isLoaded() ){
1253
        return player->getSpeed();
1254
    }
1255
    return 0.0; 
1256
}
1257

1258
float ofDirectShowPlayer::getDuration() const{
1259
    if( player && player->isLoaded() ){
1260
        return player->getDurationInSeconds();
1261
    }
1262
    return 0.0;
1263
}
1264

1265

1266
bool ofDirectShowPlayer::getIsMovieDone() const{
1267
    return ( player && player->isMovieDone() ); 
1268
}
1269
    
1270
void ofDirectShowPlayer::setPaused(bool bPause){
1271
    if( player && player->isLoaded() ){
1272
        player->setPaused(bPause);
1273
    }
1274
}
1275

1276
void ofDirectShowPlayer::setPosition(float pct){
1277
    if( player && player->isLoaded() ){
1278
        player->setPosition(pct);
1279
    }
1280
}
1281

1282
void ofDirectShowPlayer::setVolume(float volume){
1283
    if( player && player->isLoaded() ){
1284
        player->setVolume(volume);
1285
    }
1286
}
1287

1288
void ofDirectShowPlayer::setLoopState(ofLoopType state){
1289
    if( player ){
1290
        if( state == OF_LOOP_NONE ){
1291
            player->setLoop(false);
1292
        }
1293
        else if( state == OF_LOOP_NORMAL ){
1294
            player->setLoop(true);
1295
        }else{
1296
            ofLogError("ofDirectShowPlayer") << " cannot set loop of type palindrome ";
1297
        }
1298
    }
1299
}
1300

1301
void ofDirectShowPlayer::setSpeed(float speed){
1302
    if( player && player->isLoaded() ){
1303
        player->setSpeed(speed); 
1304
    }
1305
}
1306
    
1307
int ofDirectShowPlayer::getCurrentFrame() const{
1308
    if( player && player->isLoaded() ){
1309
        return player->getCurrentFrameNo();
1310
    }
1311
    return 0; 
1312
}
1313

1314
int ofDirectShowPlayer::getTotalNumFrames() const{
1315
    if( player && player->isLoaded() ){
1316
        return player->getAproximateNoFrames();
1317
    }
1318
    return 0; 
1319
}
1320

1321
ofLoopType ofDirectShowPlayer::getLoopState() const{
1322
    if( player ){
1323
        if( player->isLooping() ){
1324
            return OF_LOOP_NORMAL;
1325
        }
1326
        
1327
    }
1328
    return OF_LOOP_NONE; 
1329
}
1330

1331
void ofDirectShowPlayer::setFrame(int frame){
1332
    if( player && player->isLoaded() ){
1333
        frame = ofClamp(frame, 0, getTotalNumFrames()); 
1334
        return player->setAproximateFrame(frame);
1335
    }
1336
}  // frame 0 = first frame...
1337
    
1338
void ofDirectShowPlayer::firstFrame(){
1339
    setPosition(0.0); 
1340
}
1341

1342
void ofDirectShowPlayer::nextFrame(){
1343
    if( player && player->isLoaded() ){
1344
        player->nextFrame();
1345
    }
1346
}
1347

1348
void ofDirectShowPlayer::previousFrame(){
1349
    if( player && player->isLoaded() ){
1350
        player->preFrame();
1351
    }
1352
}
1353

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.