media-player

Форк
0
/
mf_player.cpp 
1340 строк · 31.6 Кб
1
//https://docs.microsoft.com/en-us/windows/win32/medfound/media-session-playback-example
2

3
#include <stdio.h>
4
#include <windows.h>
5
#include <shobjidl.h> 
6
#include <shlwapi.h>
7
#include <strsafe.h>
8
#include <assert.h>
9
#include <new>
10

11
// Media Foundation headers
12
#include <mfapi.h>
13
#include <mfidl.h>
14
#include <mferror.h>
15
#include <evr.h>
16

17
#pragma comment(lib, "shlwapi")
18
#pragma comment(lib, "Mf.lib")
19
#pragma comment(lib, "Mfplat.lib")
20

21
PWSTR pszFilePath = L"C:\\Media\\file.avi";
22

23
#define MY_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
24
        EXTERN_C const GUID DECLSPEC_SELECTANY name \
25
                = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
26

27
MY_DEFINE_GUID(MFMediaType_Audio,
28
0x73647561, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
29
MY_DEFINE_GUID(MFMediaType_Video,
30
0x73646976, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
31
MY_DEFINE_GUID(MF_EVENT_TOPOLOGY_STATUS,
32
0x30c5018d, 0x9a53, 0x454b, 0xad, 0x9e, 0x6d, 0x5f, 0x8f, 0xa7, 0xc4, 0x3b);
33
MY_DEFINE_GUID(MR_VIDEO_RENDER_SERVICE, 
34
    0x1092a86c, 
35
    0xab1a, 
36
    0x459a, 
37
    0xa3, 0x36, 0x83, 0x1f, 0xbc, 0x4d, 0x11, 0xff 
38
);
39

40
const UINT WM_APP_PLAYER_EVENT = WM_APP + 1; // WPARAM = IMFMediaEvent*, WPARAM = MediaEventType
41

42
template <class T> void SafeRelease(T **ppT)
43
{
44
    if (*ppT)
45
    {
46
        (*ppT)->Release();
47
        *ppT = NULL;
48
    }
49
}
50

51

52
enum PlayerState
53
{
54
    Closed = 0,     // No session.
55
    Ready,          // Session was created, ready to open a file. 
56
    OpenPending,    // Session is opening a file.
57
    Started,        // Session is playing a file.
58
    Paused,         // Session is paused.
59
    Stopped,        // Session is stopped (ready to play). 
60
    Closing         // Application has closed the session, but is waiting for MESessionClosed.
61
};
62

63
HRESULT CreateMediaSource(PCWSTR pszURL, IMFMediaSource **ppSource);
64

65
HRESULT CreatePlaybackTopology(IMFMediaSource *pSource, 
66
    IMFPresentationDescriptor *pPD, HWND hVideoWnd,IMFTopology **ppTopology);
67

68
class CPlayer : public IMFAsyncCallback
69
{
70
public:
71
    static HRESULT CreateInstance(HWND hVideo, HWND hEvent, CPlayer **ppPlayer);
72

73
    // IUnknown methods
74
    STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
75
    STDMETHODIMP_(ULONG) AddRef();
76
    STDMETHODIMP_(ULONG) Release();
77

78
    // IMFAsyncCallback methods
79
    STDMETHODIMP  GetParameters(DWORD*, DWORD*)
80
    {
81
        // Implementation of this method is optional.
82
        return E_NOTIMPL;
83
    }
84
    STDMETHODIMP  Invoke(IMFAsyncResult* pAsyncResult);
85

86
    // Playback
87
    HRESULT       OpenURL(const WCHAR *sURL);
88
    HRESULT       Play();
89
    HRESULT       Pause();
90
    HRESULT       Stop();
91
    HRESULT       Shutdown();
92
    HRESULT       HandleEvent(UINT_PTR pUnkPtr);
93
    PlayerState   GetState() const { return m_state; }
94

95
    // Video functionality
96
    HRESULT       Repaint();
97
    HRESULT       ResizeVideo(WORD width, WORD height);
98
    
99
    BOOL          HasVideo() const { return (m_pVideoDisplay != NULL);  }
100

101
protected:
102
    
103
    // Constructor is private. Use static CreateInstance method to instantiate.
104
    CPlayer(HWND hVideo, HWND hEvent);
105

106
    // Destructor is private. Caller should call Release.
107
    virtual ~CPlayer(); 
108

109
    HRESULT Initialize();
110
    HRESULT CreateSession();
111
    HRESULT CloseSession();
112
    HRESULT StartPlayback();
113

114
    // Media event handlers
115
    virtual HRESULT OnTopologyStatus(IMFMediaEvent *pEvent);
116
    virtual HRESULT OnPresentationEnded(IMFMediaEvent *pEvent);
117
    virtual HRESULT OnNewPresentation(IMFMediaEvent *pEvent);
118

119
    // Override to handle additional session events.
120
    virtual HRESULT OnSessionEvent(IMFMediaEvent*, MediaEventType) 
121
    { 
122
        return S_OK; 
123
    }
124

125
protected:
126
    long                    m_nRefCount;        // Reference count.
127

128
    IMFMediaSession         *m_pSession;
129
    IMFMediaSource          *m_pSource;
130
    IMFVideoDisplayControl  *m_pVideoDisplay;
131

132
    HWND                    m_hwndVideo;        // Video window.
133
    HWND                    m_hwndEvent;        // App window to receive events.
134
    PlayerState             m_state;            // Current state of the media session.
135
    HANDLE                  m_hCloseEvent;      // Event to wait on while closing.
136
};
137

138
template <class Q>
139
HRESULT GetEventObject(IMFMediaEvent *pEvent, Q **ppObject)
140
{
141
    *ppObject = NULL;   // zero output
142

143
    PROPVARIANT var;
144
    HRESULT hr = pEvent->GetValue(&var);
145
    if (SUCCEEDED(hr))
146
    {
147
        if (var.vt == VT_UNKNOWN)
148
        {
149
            hr = var.punkVal->QueryInterface(ppObject);
150
        }
151
        else
152
        {
153
            hr = MF_E_INVALIDTYPE;
154
        }
155
        PropVariantClear(&var);
156
    }
157
    return hr;
158
}
159

160
HRESULT CreateMediaSource(PCWSTR pszURL, IMFMediaSource **ppSource);
161

162
HRESULT CreatePlaybackTopology(IMFMediaSource *pSource, 
163
    IMFPresentationDescriptor *pPD, HWND hVideoWnd,IMFTopology **ppTopology);
164

165
//  Static class method to create the CPlayer object.
166

167
HRESULT CPlayer::CreateInstance(
168
    HWND hVideo,                  // Video window.
169
    HWND hEvent,                  // Window to receive notifications.
170
    CPlayer **ppPlayer)           // Receives a pointer to the CPlayer object.
171
{
172
    if (ppPlayer == NULL)
173
    {
174
        return E_POINTER;
175
    }
176

177
    CPlayer *pPlayer = new (std::nothrow) CPlayer(hVideo, hEvent);
178
    if (pPlayer == NULL)
179
    {
180
        return E_OUTOFMEMORY;
181
    }
182

183
    HRESULT hr = pPlayer->Initialize();
184
    if (SUCCEEDED(hr))
185
    {
186
        *ppPlayer = pPlayer;
187
    }
188
    else
189
    {
190
        pPlayer->Release();
191
    }
192
    return hr;
193
}
194

195
HRESULT CPlayer::Initialize()
196
{
197
    // Start up Media Foundation platform.
198
    HRESULT hr = MFStartup(MF_VERSION);
199
    if (SUCCEEDED(hr))
200
    {
201
        m_hCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
202
        if (m_hCloseEvent == NULL)
203
        {
204
            hr = HRESULT_FROM_WIN32(GetLastError());
205
        }
206
    }
207
    return hr;
208
}
209

210
CPlayer::CPlayer(HWND hVideo, HWND hEvent) : 
211
    m_pSession(NULL),
212
    m_pSource(NULL),
213
    m_pVideoDisplay(NULL),
214
    m_hwndVideo(hVideo),
215
    m_hwndEvent(hEvent),
216
    m_state(Closed),
217
    m_hCloseEvent(NULL),
218
    m_nRefCount(1)
219
{
220
}
221

222
CPlayer::~CPlayer()
223
{
224
    assert(m_pSession == NULL);  
225
    // If FALSE, the app did not call Shutdown().
226

227
    // When CPlayer calls IMediaEventGenerator::BeginGetEvent on the
228
    // media session, it causes the media session to hold a reference 
229
    // count on the CPlayer. 
230
    
231
    // This creates a circular reference count between CPlayer and the 
232
    // media session. Calling Shutdown breaks the circular reference 
233
    // count.
234

235
    // If CreateInstance fails, the application will not call 
236
    // Shutdown. To handle that case, call Shutdown in the destructor. 
237

238
    Shutdown();
239
}
240

241
// IUnknown methods
242

243
HRESULT CPlayer::QueryInterface(REFIID riid, void** ppv)
244
{
245
    static const QITAB qit[] = 
246
    {
247
        QITABENT(CPlayer, IMFAsyncCallback),
248
        { 0 }
249
    };
250
    return QISearch(this, qit, riid, ppv);
251
}
252

253
ULONG CPlayer::AddRef()
254
{
255
    return InterlockedIncrement(&m_nRefCount);
256
}
257

258
ULONG CPlayer::Release()
259
{
260
    ULONG uCount = InterlockedDecrement(&m_nRefCount);
261
    if (uCount == 0)
262
    {
263
        delete this;
264
    }
265
    return uCount;
266
}
267

268
//  Open a URL for playback.
269
HRESULT CPlayer::OpenURL(const WCHAR *sURL)
270
{
271
    // 1. Create a new media session.
272
    // 2. Create the media source.
273
    // 3. Create the topology.
274
    // 4. Queue the topology [asynchronous]
275
    // 5. Start playback [asynchronous - does not happen in this method.]
276

277
    IMFTopology *pTopology = NULL;
278
    IMFPresentationDescriptor* pSourcePD = NULL;
279

280
    // Create the media session.
281
    HRESULT hr = CreateSession();
282
    if (FAILED(hr))
283
    {
284
        goto done;
285
    }
286

287
    // Create the media source.
288
    hr = CreateMediaSource(sURL, &m_pSource);
289
    if (FAILED(hr))
290
    {
291
        goto done;
292
    }
293

294
    // Create the presentation descriptor for the media source.
295
    hr = m_pSource->CreatePresentationDescriptor(&pSourcePD);
296
    if (FAILED(hr))
297
    {
298
        goto done;
299
    }
300

301
    // Create a partial topology.
302
    hr = CreatePlaybackTopology(m_pSource, pSourcePD, m_hwndVideo, &pTopology);
303
    if (FAILED(hr))
304
    {
305
        goto done;
306
    }
307

308
    // Set the topology on the media session.
309
    hr = m_pSession->SetTopology(0, pTopology);
310
    if (FAILED(hr))
311
    {
312
        goto done;
313
    }
314

315
    m_state = OpenPending;
316

317
    // If SetTopology succeeds, the media session will queue an 
318
    // MESessionTopologySet event.
319

320
done:
321
    if (FAILED(hr))
322
    {
323
        m_state = Closed;
324
    }
325

326
    SafeRelease(&pSourcePD);
327
    SafeRelease(&pTopology);
328
    return hr;
329
}
330

331
//  Pause playback.
332
HRESULT CPlayer::Pause()    
333
{
334
    if (m_state != Started)
335
    {
336
        return MF_E_INVALIDREQUEST;
337
    }
338
    if (m_pSession == NULL || m_pSource == NULL)
339
    {
340
        return E_UNEXPECTED;
341
    }
342

343
    HRESULT hr = m_pSession->Pause();
344
    if (SUCCEEDED(hr))
345
    {
346
        m_state = Paused;
347
    }
348

349
    return hr;
350
}
351

352
// Stop playback.
353
HRESULT CPlayer::Stop()
354
{
355
    if (m_state != Started && m_state != Paused)
356
    {
357
        return MF_E_INVALIDREQUEST;
358
    }
359
    if (m_pSession == NULL)
360
    {
361
        return E_UNEXPECTED;
362
    }
363

364
    HRESULT hr = m_pSession->Stop();
365
    if (SUCCEEDED(hr))
366
    {
367
        m_state = Stopped;
368
    }
369
    return hr;
370
}
371

372
//  Repaint the video window. Call this method on WM_PAINT.
373

374
HRESULT CPlayer::Repaint()
375
{
376
    if (m_pVideoDisplay)
377
    {
378
        return m_pVideoDisplay->RepaintVideo();
379
    }
380
    else
381
    {
382
        return S_OK;
383
    }
384
}
385

386
//  Resize the video rectangle.
387
//
388
//  Call this method if the size of the video window changes.
389

390
HRESULT CPlayer::ResizeVideo(WORD width, WORD height)
391
{
392
    if (m_pVideoDisplay)
393
    {
394
        // Set the destination rectangle.
395
        // Leave the default source rectangle (0,0,1,1).
396

397
        RECT rcDest = { 0, 0, width, height };
398

399
        return m_pVideoDisplay->SetVideoPosition(NULL, &rcDest);
400
    }
401
    else
402
    {
403
        return S_OK;
404
    }
405
}
406

407
//  Callback for the asynchronous BeginGetEvent method.
408

409
HRESULT CPlayer::Invoke(IMFAsyncResult *pResult)
410
{
411
    MediaEventType meType = MEUnknown;  // Event type
412

413
    IMFMediaEvent *pEvent = NULL;
414

415
    // Get the event from the event queue.
416
    HRESULT hr = m_pSession->EndGetEvent(pResult, &pEvent);
417
    if (FAILED(hr))
418
    {
419
        goto done;
420
    }
421

422
    // Get the event type. 
423
    hr = pEvent->GetType(&meType);
424
    if (FAILED(hr))
425
    {
426
        goto done;
427
    }
428

429
    if (meType == MESessionClosed)
430
    {
431
        // The session was closed. 
432
        // The application is waiting on the m_hCloseEvent event handle. 
433
        SetEvent(m_hCloseEvent);
434
    }
435
    else
436
    {
437
        // For all other events, get the next event in the queue.
438
        hr = m_pSession->BeginGetEvent(this, NULL);
439
        if (FAILED(hr))
440
        {
441
            goto done;
442
        }
443
    }
444

445
    // Check the application state. 
446
        
447
    // If a call to IMFMediaSession::Close is pending, it means the 
448
    // application is waiting on the m_hCloseEvent event and
449
    // the application's message loop is blocked. 
450

451
    // Otherwise, post a private window message to the application. 
452

453
    if (m_state != Closing)
454
    {
455
        // Leave a reference count on the event.
456
        pEvent->AddRef();
457

458
        PostMessage(m_hwndEvent, WM_APP_PLAYER_EVENT, 
459
            (WPARAM)pEvent, (LPARAM)meType);
460
    }
461

462
done:
463
    SafeRelease(&pEvent);
464
    return S_OK;
465
}
466

467
HRESULT CPlayer::HandleEvent(UINT_PTR pEventPtr)
468
{
469
    HRESULT hrStatus = S_OK;            
470
    MediaEventType meType = MEUnknown;  
471

472
    IMFMediaEvent *pEvent = (IMFMediaEvent*)pEventPtr;
473

474
    if (pEvent == NULL)
475
    {
476
        return E_POINTER;
477
    }
478

479
    // Get the event type.
480
    HRESULT hr = pEvent->GetType(&meType);
481
    if (FAILED(hr))
482
    {
483
        goto done;
484
    }
485

486
    // Get the event status. If the operation that triggered the event 
487
    // did not succeed, the status is a failure code.
488
    hr = pEvent->GetStatus(&hrStatus);
489

490
    // Check if the async operation succeeded.
491
    if (SUCCEEDED(hr) && FAILED(hrStatus)) 
492
    {
493
        hr = hrStatus;
494
    }
495
    if (FAILED(hr))
496
    {
497
        goto done;
498
    }
499

500
    switch(meType)
501
    {
502
    case MESessionTopologyStatus:
503
        hr = OnTopologyStatus(pEvent);
504
        break;
505

506
    case MEEndOfPresentation:
507
        hr = OnPresentationEnded(pEvent);
508
        break;
509

510
    case MENewPresentation:
511
        hr = OnNewPresentation(pEvent);
512
        break;
513

514
    default:
515
        hr = OnSessionEvent(pEvent, meType);
516
        break;
517
    }
518

519
done:
520
    SafeRelease(&pEvent);
521
    return hr;
522
}
523

524
//  Release all resources held by this object.
525
HRESULT CPlayer::Shutdown()
526
{
527
    // Close the session
528
    HRESULT hr = CloseSession();
529

530
    // Shutdown the Media Foundation platform
531
    MFShutdown();
532

533
    if (m_hCloseEvent)
534
    {
535
        CloseHandle(m_hCloseEvent);
536
        m_hCloseEvent = NULL;
537
    }
538

539
    return hr;
540
}
541

542
/// Protected methods
543

544
HRESULT CPlayer::OnTopologyStatus(IMFMediaEvent *pEvent)
545
{
546
    UINT32 status; 
547

548
    HRESULT hr = pEvent->GetUINT32(MF_EVENT_TOPOLOGY_STATUS, &status);
549
    if (SUCCEEDED(hr) && (status == MF_TOPOSTATUS_READY))
550
    {
551
        SafeRelease(&m_pVideoDisplay);
552

553
        // Get the IMFVideoDisplayControl interface from EVR. This call is
554
        // expected to fail if the media file does not have a video stream.
555

556
        (void)MFGetService(m_pSession, MR_VIDEO_RENDER_SERVICE, 
557
            IID_PPV_ARGS(&m_pVideoDisplay));
558

559
        hr = StartPlayback();
560
    }
561
    return hr;
562
}
563

564

565
//  Handler for MEEndOfPresentation event.
566
HRESULT CPlayer::OnPresentationEnded(IMFMediaEvent *pEvent)
567
{
568
    // The session puts itself into the stopped state automatically.
569
    m_state = Stopped;
570
    return S_OK;
571
}
572

573
//  Handler for MENewPresentation event.
574
//
575
//  This event is sent if the media source has a new presentation, which 
576
//  requires a new topology. 
577

578
HRESULT CPlayer::OnNewPresentation(IMFMediaEvent *pEvent)
579
{
580
    IMFPresentationDescriptor *pPD = NULL;
581
    IMFTopology *pTopology = NULL;
582

583
    // Get the presentation descriptor from the event.
584
    HRESULT hr = GetEventObject(pEvent, &pPD);
585
    if (FAILED(hr))
586
    {
587
        goto done;
588
    }
589

590
    // Create a partial topology.
591
    hr = CreatePlaybackTopology(m_pSource, pPD,  m_hwndVideo,&pTopology);
592
    if (FAILED(hr))
593
    {
594
        goto done;
595
    }
596

597
    // Set the topology on the media session.
598
    hr = m_pSession->SetTopology(0, pTopology);
599
    if (FAILED(hr))
600
    {
601
        goto done;
602
    }
603

604
    m_state = OpenPending;
605

606
done:
607
    SafeRelease(&pTopology);
608
    SafeRelease(&pPD);
609
    return S_OK;
610
}
611

612
//  Create a new instance of the media session.
613
HRESULT CPlayer::CreateSession()
614
{
615
    // Close the old session, if any.
616
    HRESULT hr = CloseSession();
617
    if (FAILED(hr))
618
    {
619
        goto done;
620
    }
621

622
    assert(m_state == Closed);
623

624
    // Create the media session.
625
    hr = MFCreateMediaSession(NULL, &m_pSession);
626
    if (FAILED(hr))
627
    {
628
        goto done;
629
    }
630

631
    // Start pulling events from the media session
632
    hr = m_pSession->BeginGetEvent((IMFAsyncCallback*)this, NULL);
633
    if (FAILED(hr))
634
    {
635
        goto done;
636
    }
637

638
    m_state = Ready;
639

640
done:
641
    return hr;
642
}
643

644
//  Close the media session. 
645
HRESULT CPlayer::CloseSession()
646
{
647
    //  The IMFMediaSession::Close method is asynchronous, but the 
648
    //  CPlayer::CloseSession method waits on the MESessionClosed event.
649
    //  
650
    //  MESessionClosed is guaranteed to be the last event that the 
651
    //  media session fires.
652

653
    HRESULT hr = S_OK;
654

655
    SafeRelease(&m_pVideoDisplay);
656

657
    // First close the media session.
658
    if (m_pSession)
659
    {
660
        DWORD dwWaitResult = 0;
661

662
        m_state = Closing;
663
           
664
        hr = m_pSession->Close();
665
        // Wait for the close operation to complete
666
        if (SUCCEEDED(hr))
667
        {
668
            dwWaitResult = WaitForSingleObject(m_hCloseEvent, 5000);
669
            if (dwWaitResult == WAIT_TIMEOUT)
670
            {
671
                assert(FALSE);
672
            }
673
            // Now there will be no more events from this session.
674
        }
675
    }
676

677
    // Complete shutdown operations.
678
    if (SUCCEEDED(hr))
679
    {
680
        // Shut down the media source. (Synchronous operation, no events.)
681
        if (m_pSource)
682
        {
683
            (void)m_pSource->Shutdown();
684
        }
685
        // Shut down the media session. (Synchronous operation, no events.)
686
        if (m_pSession)
687
        {
688
            (void)m_pSession->Shutdown();
689
        }
690
    }
691

692
    SafeRelease(&m_pSource);
693
    SafeRelease(&m_pSession);
694
    m_state = Closed;
695
    return hr;
696
}
697

698
//  Start playback from the current position. 
699
HRESULT CPlayer::StartPlayback()
700
{
701
    assert(m_pSession != NULL);
702

703
    PROPVARIANT varStart;
704
    PropVariantInit(&varStart);
705

706
    HRESULT hr = m_pSession->Start(&GUID_NULL, &varStart);
707
    if (SUCCEEDED(hr))
708
    {
709
        // Note: Start is an asynchronous operation. However, we
710
        // can treat our state as being already started. If Start
711
        // fails later, we'll get an MESessionStarted event with
712
        // an error code, and we will update our state then.
713
        m_state = Started;
714
    }
715
    PropVariantClear(&varStart);
716
    return hr;
717
}
718

719
//  Start playback from paused or stopped.
720
HRESULT CPlayer::Play()
721
{
722
    if (m_state != Paused && m_state != Stopped)
723
    {
724
        return MF_E_INVALIDREQUEST;
725
    }
726
    if (m_pSession == NULL || m_pSource == NULL)
727
    {
728
        return E_UNEXPECTED;
729
    }
730
    return StartPlayback();
731
}
732

733

734
//  Create a media source from a URL.
735
HRESULT CreateMediaSource(PCWSTR sURL, IMFMediaSource **ppSource)
736
{
737
    MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
738

739
    IMFSourceResolver* pSourceResolver = NULL;
740
    IUnknown* pSource = NULL;
741

742
    // Create the source resolver.
743
    HRESULT hr = MFCreateSourceResolver(&pSourceResolver);
744
    if (FAILED(hr))
745
    {
746
        goto done;
747
    }
748

749
    // Use the source resolver to create the media source.
750

751
    // Note: For simplicity this sample uses the synchronous method to create 
752
    // the media source. However, creating a media source can take a noticeable
753
    // amount of time, especially for a network source. For a more responsive 
754
    // UI, use the asynchronous BeginCreateObjectFromURL method.
755

756
    hr = pSourceResolver->CreateObjectFromURL(
757
        sURL,                       // URL of the source.
758
        MF_RESOLUTION_MEDIASOURCE,  // Create a source object.
759
        NULL,                       // Optional property store.
760
        &ObjectType,        // Receives the created object type. 
761
        &pSource            // Receives a pointer to the media source.
762
        );
763
    if (FAILED(hr))
764
    {
765
        goto done;
766
    }
767

768
    // Get the IMFMediaSource interface from the media source.
769
    hr = pSource->QueryInterface(IID_PPV_ARGS(ppSource));
770

771
done:
772
    SafeRelease(&pSourceResolver);
773
    SafeRelease(&pSource);
774
    return hr;
775
}
776

777
//  Create an activation object for a renderer, based on the stream media type.
778

779
HRESULT CreateMediaSinkActivate(
780
    IMFStreamDescriptor *pSourceSD,     // Pointer to the stream descriptor.
781
    HWND hVideoWindow,                  // Handle to the video clipping window.
782
    IMFActivate **ppActivate
783
)
784
{
785
    IMFMediaTypeHandler *pHandler = NULL;
786
    IMFActivate *pActivate = NULL;
787

788
    // Get the media type handler for the stream.
789
    HRESULT hr = pSourceSD->GetMediaTypeHandler(&pHandler);
790
    if (FAILED(hr))
791
    {
792
        goto done;
793
    }
794

795
    // Get the major media type.
796
    GUID guidMajorType;
797
    hr = pHandler->GetMajorType(&guidMajorType);
798
    if (FAILED(hr))
799
    {
800
        goto done;
801
    }
802
 
803
    // Create an IMFActivate object for the renderer, based on the media type.
804
    if (MFMediaType_Audio == guidMajorType)
805
    {
806
        // Create the audio renderer.
807
        hr = MFCreateAudioRendererActivate(&pActivate);
808
    }
809
    else if (MFMediaType_Video == guidMajorType)
810
    {
811
        // Create the video renderer.
812
        hr = MFCreateVideoRendererActivate(hVideoWindow, &pActivate);
813
    }
814
    else
815
    {
816
        // Unknown stream type. 
817
        hr = E_FAIL;
818
        // Optionally, you could deselect this stream instead of failing.
819
    }
820
    if (FAILED(hr))
821
    {
822
        goto done;
823
    }
824
 
825
    // Return IMFActivate pointer to caller.
826
    *ppActivate = pActivate;
827
    (*ppActivate)->AddRef();
828

829
done:
830
    SafeRelease(&pHandler);
831
    SafeRelease(&pActivate);
832
    return hr;
833
}
834

835
// Add a source node to a topology.
836
HRESULT AddSourceNode(
837
    IMFTopology *pTopology,           // Topology.
838
    IMFMediaSource *pSource,          // Media source.
839
    IMFPresentationDescriptor *pPD,   // Presentation descriptor.
840
    IMFStreamDescriptor *pSD,         // Stream descriptor.
841
    IMFTopologyNode **ppNode)         // Receives the node pointer.
842
{
843
    IMFTopologyNode *pNode = NULL;
844

845
    // Create the node.
846
    HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode);
847
    if (FAILED(hr))
848
    {
849
        goto done;
850
    }
851

852
    // Set the attributes.
853
    hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource);
854
    if (FAILED(hr))
855
    {
856
        goto done;
857
    }
858

859
    hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD);
860
    if (FAILED(hr))
861
    {
862
        goto done;
863
    }
864

865
    hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD);
866
    if (FAILED(hr))
867
    {
868
        goto done;
869
    }
870
    
871
    // Add the node to the topology.
872
    hr = pTopology->AddNode(pNode);
873
    if (FAILED(hr))
874
    {
875
        goto done;
876
    }
877

878
    // Return the pointer to the caller.
879
    *ppNode = pNode;
880
    (*ppNode)->AddRef();
881

882
done:
883
    SafeRelease(&pNode);
884
    return hr;
885
}
886

887
// Add an output node to a topology.
888
HRESULT AddOutputNode(
889
    IMFTopology *pTopology,     // Topology.
890
    IMFActivate *pActivate,     // Media sink activation object.
891
    DWORD dwId,                 // Identifier of the stream sink.
892
    IMFTopologyNode **ppNode)   // Receives the node pointer.
893
{
894
    IMFTopologyNode *pNode = NULL;
895

896
    // Create the node.
897
    HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode);
898
    if (FAILED(hr))
899
    {
900
        goto done;
901
    }
902

903
    // Set the object pointer.
904
    hr = pNode->SetObject(pActivate);
905
    if (FAILED(hr))
906
    {
907
        goto done;
908
    }
909

910
    // Set the stream sink ID attribute.
911
    hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId);
912
    if (FAILED(hr))
913
    {
914
        goto done;
915
    }
916

917
    hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
918
    if (FAILED(hr))
919
    {
920
        goto done;
921
    }
922

923
    // Add the node to the topology.
924
    hr = pTopology->AddNode(pNode);
925
    if (FAILED(hr))
926
    {
927
        goto done;
928
    }
929

930
    // Return the pointer to the caller.
931
    *ppNode = pNode;
932
    (*ppNode)->AddRef();
933

934
done:
935
    SafeRelease(&pNode);
936
    return hr;
937
}
938
//</SnippetPlayer.cpp>
939

940
//  Add a topology branch for one stream.
941
//
942
//  For each stream, this function does the following:
943
//
944
//    1. Creates a source node associated with the stream. 
945
//    2. Creates an output node for the renderer. 
946
//    3. Connects the two nodes.
947
//
948
//  The media session will add any decoders that are needed.
949

950
HRESULT AddBranchToPartialTopology(
951
    IMFTopology *pTopology,         // Topology.
952
    IMFMediaSource *pSource,        // Media source.
953
    IMFPresentationDescriptor *pPD, // Presentation descriptor.
954
    DWORD iStream,                  // Stream index.
955
    HWND hVideoWnd)                 // Window for video playback.
956
{
957
    IMFStreamDescriptor *pSD = NULL;
958
    IMFActivate         *pSinkActivate = NULL;
959
    IMFTopologyNode     *pSourceNode = NULL;
960
    IMFTopologyNode     *pOutputNode = NULL;
961

962
    BOOL fSelected = FALSE;
963

964
    HRESULT hr = pPD->GetStreamDescriptorByIndex(iStream, &fSelected, &pSD);
965
    if (FAILED(hr))
966
    {
967
        goto done;
968
    }
969

970
    if (fSelected)
971
    {
972
        // Create the media sink activation object.
973
        hr = CreateMediaSinkActivate(pSD, hVideoWnd, &pSinkActivate);
974
        if (FAILED(hr))
975
        {
976
            goto done;
977
        }
978

979
        // Add a source node for this stream.
980
        hr = AddSourceNode(pTopology, pSource, pPD, pSD, &pSourceNode);
981
        if (FAILED(hr))
982
        {
983
            goto done;
984
        }
985

986
        // Create the output node for the renderer.
987
        hr = AddOutputNode(pTopology, pSinkActivate, 0, &pOutputNode);
988
        if (FAILED(hr))
989
        {
990
            goto done;
991
        }
992

993
        // Connect the source node to the output node.
994
        hr = pSourceNode->ConnectOutput(0, pOutputNode, 0);
995
    }
996
    // else: If not selected, don't add the branch. 
997

998
done:
999
    SafeRelease(&pSD);
1000
    SafeRelease(&pSinkActivate);
1001
    SafeRelease(&pSourceNode);
1002
    SafeRelease(&pOutputNode);
1003
    return hr;
1004
}
1005

1006
//  Create a playback topology from a media source.
1007
HRESULT CreatePlaybackTopology(
1008
    IMFMediaSource *pSource,          // Media source.
1009
    IMFPresentationDescriptor *pPD,   // Presentation descriptor.
1010
    HWND hVideoWnd,                   // Video window.
1011
    IMFTopology **ppTopology)         // Receives a pointer to the topology.
1012
{
1013
    IMFTopology *pTopology = NULL;
1014
    DWORD cSourceStreams = 0;
1015

1016
    // Create a new topology.
1017
    HRESULT hr = MFCreateTopology(&pTopology);
1018
    if (FAILED(hr))
1019
    {
1020
        goto done;
1021
    }
1022

1023

1024

1025

1026
    // Get the number of streams in the media source.
1027
    hr = pPD->GetStreamDescriptorCount(&cSourceStreams);
1028
    if (FAILED(hr))
1029
    {
1030
        goto done;
1031
    }
1032

1033
    // For each stream, create the topology nodes and add them to the topology.
1034
    for (DWORD i = 0; i < cSourceStreams; i++)
1035
    {
1036
        hr = AddBranchToPartialTopology(pTopology, pSource, pPD, i, hVideoWnd);
1037
        if (FAILED(hr))
1038
        {
1039
            goto done;
1040
        }
1041
    }
1042

1043
    // Return the IMFTopology pointer to the caller.
1044
    *ppTopology = pTopology;
1045
    (*ppTopology)->AddRef();
1046

1047
done:
1048
    SafeRelease(&pTopology);
1049
    return hr;
1050
}
1051

1052
//***** Application *********
1053

1054
PCWSTR szTitle = L"BasicPlayback";
1055
PCWSTR szWindowClass = L"MFBASICPLAYBACK";
1056

1057
HINSTANCE   g_hInstance;                        // current instance
1058
BOOL        g_bRepaintClient = TRUE;            // Repaint the application client area?
1059
CPlayer     *g_pPlayer = NULL;                  // Global player object. 
1060
HWND hWnd=NULL;
1061

1062
// Note: After WM_CREATE is processed, g_pPlayer remains valid until the
1063
// window is destroyed.
1064

1065
// Forward declarations of functions included in this code module:
1066
BOOL                InitInstance(HINSTANCE, int);
1067
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
1068
INT_PTR CALLBACK    OpenUrlDialogProc(HWND, UINT, WPARAM, LPARAM);
1069
void                NotifyError(HWND hwnd, const WCHAR *sErrorMessage, HRESULT hr);
1070
void                UpdateUI(HWND hwnd, PlayerState state);
1071
HRESULT             AllocGetWindowText(HWND hwnd, WCHAR **pszText, DWORD *pcchLen);
1072

1073
// Message handlers
1074
LRESULT             OnCreateWindow(HWND hwnd);
1075
void                OnFileOpen(HWND hwnd);
1076
void                OnOpenURL(HWND hwnd);
1077
void                OnPlayerEvent(HWND hwnd, WPARAM pUnkPtr);
1078
void                OnPaint(HWND hwnd);
1079
void                OnResize(WORD width, WORD height);
1080
void                OnKeyPress(WPARAM key);
1081

1082
//  Create the application window.
1083
BOOL InitInstance(HINSTANCE hInst, int nCmdShow)
1084
{    
1085
    WNDCLASSEX wcex;
1086

1087
    g_hInstance = hInst; // Store the instance handle.
1088

1089
    // Register the window class.
1090
    ZeroMemory(&wcex, sizeof(WNDCLASSEX));
1091
    wcex.cbSize         = sizeof(WNDCLASSEX);
1092
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
1093
    wcex.lpfnWndProc    = WndProc;
1094
    wcex.hInstance      = hInst;
1095
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
1096
    wcex.lpszMenuName   = NULL;
1097
	wcex.hCursor = LoadCursor(NULL,IDC_ARROW);
1098
    wcex.lpszClassName  = szWindowClass;
1099

1100
    if (RegisterClassEx(&wcex) == 0)
1101
    {
1102
        return FALSE;
1103
    }
1104

1105
    // Create the application window.
1106
    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
1107
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
1108

1109
    if (hWnd == 0)
1110
    {
1111
        return FALSE;
1112
    }
1113

1114
    ShowWindow(hWnd, nCmdShow);
1115
    UpdateWindow(hWnd);
1116

1117
    return TRUE;
1118
}
1119

1120
//  Message handler for the main window.
1121

1122
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1123
{
1124
	LRESULT res=0;
1125

1126
    switch (message)
1127
    {
1128
    case WM_CREATE:
1129
        res= OnCreateWindow(hwnd);
1130
		
1131
		return res;
1132

1133
    case WM_PAINT:
1134
        OnPaint(hwnd);
1135
        break;
1136

1137
    case WM_SIZE:
1138
        OnResize(LOWORD(lParam), HIWORD(lParam));
1139
        break;
1140

1141
    case WM_ERASEBKGND:
1142
        // Suppress window erasing, to reduce flickering while the video is playing.
1143
        return 1;
1144

1145
    case WM_DESTROY:
1146
        PostQuitMessage(0);
1147
        break;
1148

1149
    case WM_CHAR:
1150
		
1151
        OnKeyPress(wParam);
1152
        break;
1153

1154
    case WM_APP_PLAYER_EVENT:
1155
        OnPlayerEvent(hwnd, wParam);
1156
        break;
1157

1158
    default:
1159
        return DefWindowProc(hwnd, message, wParam, lParam);
1160
    }
1161
    return 0;
1162
}
1163

1164
//  Open an audio/video file.
1165
void OnFileOpen(PWSTR file)
1166
{
1167
    // Display the file name to the user.
1168
    HRESULT hr = g_pPlayer->OpenURL(file);
1169
    if (SUCCEEDED(hr))
1170
    {
1171
        UpdateUI(hWnd, OpenPending);
1172
    }
1173

1174
done:
1175
    if (FAILED(hr))
1176
    {
1177
        NotifyError(hWnd, L"Could not open the file.", hr);
1178
        UpdateUI(hWnd, Closed);
1179
    }    
1180
}
1181

1182
//  Handler for WM_CREATE message.
1183
LRESULT OnCreateWindow(HWND hwnd)
1184
{
1185
    // Initialize the player object.
1186
    HRESULT hr = CPlayer::CreateInstance(hwnd, hwnd, &g_pPlayer); 
1187
    if (SUCCEEDED(hr))
1188
    {
1189
        UpdateUI(hwnd, Closed);
1190
        return 0;   // Success.
1191
    }
1192
    else
1193
    {
1194
        NotifyError(NULL, L"Could not initialize the player object.", hr);
1195
        return -1;  // Destroy the window
1196
    }
1197
}
1198

1199
//  Handler for WM_PAINT messages.
1200
void OnPaint(HWND hwnd)
1201
{
1202
    PAINTSTRUCT ps;
1203
    HDC hdc = BeginPaint(hwnd, &ps);
1204

1205
    if (g_pPlayer && g_pPlayer->HasVideo())
1206
    {
1207
        // Video is playing. Ask the player to repaint.
1208
        g_pPlayer->Repaint();
1209
    }
1210
    else
1211
    {
1212
        // The video is not playing, so we must paint the application window.
1213
        RECT rc;
1214
        GetClientRect(hwnd, &rc);
1215
        FillRect(hdc, &rc, (HBRUSH) COLOR_WINDOW);
1216
    }
1217
    EndPaint(hwnd, &ps);
1218
}
1219

1220
//  Handler for WM_SIZE messages.
1221
void OnResize(WORD width, WORD height)
1222
{
1223
    if (g_pPlayer)
1224
    {
1225
        g_pPlayer->ResizeVideo(width, height);
1226
    }
1227
}
1228

1229

1230
// Handler for WM_CHAR messages. 
1231
void OnKeyPress(WPARAM key)
1232
{
1233
    switch (key)
1234
    {		
1235
    // Space key toggles between running and paused
1236
    case VK_SPACE:
1237
        if (g_pPlayer->GetState() == Started)
1238
        {
1239
            g_pPlayer->Pause();
1240
        }
1241
        else if (g_pPlayer->GetState() == Paused)
1242
        {
1243
            g_pPlayer->Play();
1244
        }
1245
        break;
1246
    }
1247
}
1248

1249
// Update the application UI to reflect the current state.
1250

1251
void UpdateUI(HWND hwnd, PlayerState state)
1252
{
1253
    BOOL bWaiting = FALSE;
1254
    BOOL bPlayback = FALSE;
1255

1256
    assert(g_pPlayer != NULL);
1257

1258
    switch (state)
1259
    {
1260
    case OpenPending:
1261
        bWaiting = TRUE;
1262
        break;
1263

1264
    case Started:
1265
        bPlayback = TRUE;
1266
        break;
1267

1268
    case Paused:
1269
        bPlayback = TRUE;
1270
        break;
1271
    }
1272

1273
    if (bPlayback && g_pPlayer->HasVideo())
1274
    {
1275
        g_bRepaintClient = FALSE;
1276
    }
1277
    else
1278
    {
1279
        g_bRepaintClient = TRUE;
1280
    }
1281
}
1282

1283
//  Show a message box with an error message.
1284
void NotifyError(HWND hwnd, PCWSTR pszErrorMessage, HRESULT hrErr)
1285
{
1286
    const size_t MESSAGE_LEN = 512;
1287
    WCHAR message[MESSAGE_LEN];
1288

1289
    if (SUCCEEDED(StringCchPrintf(message, MESSAGE_LEN, L"%s (HRESULT = 0x%X)", 
1290
        pszErrorMessage, hrErr)))
1291
    {
1292
        MessageBox(hwnd, message, NULL, MB_OK | MB_ICONERROR);
1293
    }
1294
}
1295

1296
// Handler for Media Session events.
1297
void OnPlayerEvent(HWND hwnd, WPARAM pUnkPtr)
1298
{
1299
    HRESULT hr = g_pPlayer->HandleEvent(pUnkPtr);
1300
    if (FAILED(hr))
1301
    {
1302
        NotifyError(hwnd, L"OnPlayerEvent error", hr);
1303
    }
1304
    UpdateUI(hwnd, g_pPlayer->GetState());
1305
}
1306

1307
//*******************************************************
1308

1309
int main()
1310
{
1311
	// Perform application initialization.
1312
    if (!InitInstance(GetModuleHandle(NULL), SW_SHOW))
1313
    {
1314
        NotifyError(NULL, L"Could not initialize the application.", 
1315
            HRESULT_FROM_WIN32(GetLastError()));
1316
        return FALSE;
1317
    }
1318

1319
	OnFileOpen(pszFilePath);
1320
	g_pPlayer->Play();
1321
	
1322
	MSG msg;
1323
    ZeroMemory(&msg, sizeof(msg));
1324

1325
	// Main message loop.
1326
    while (GetMessage(&msg, NULL, 0, 0))
1327
    {
1328
        TranslateMessage(&msg);
1329
        DispatchMessage(&msg);
1330
    }
1331

1332
	// Clean up.
1333
    if (g_pPlayer)
1334
    {
1335
        g_pPlayer->Shutdown();
1336
        SafeRelease(&g_pPlayer);
1337
    }
1338
    
1339
	return 0;
1340
}
1341

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

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

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

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