framework2

Форк
0
/
ofMediaFoundationPlayer.cpp 
1384 строки · 45.5 Кб
1

2
#include "ofPixels.h"
3
#include "ofMediaFoundationPlayer.h"
4
#include "ofLog.h"
5
#include <string.h>
6
#include <mfapi.h>
7
#include <mferror.h>
8
#include "ofTexture.h"
9
#include "ofGLUtils.h"
10
#include "ofGraphics.h"
11
#include "ofEventUtils.h"
12

13
// declares some shared Media Foundation code
14
#include "ofMediaFoundationSoundPlayer.h"
15

16
using namespace Microsoft::WRL;
17

18
std::shared_ptr<ofMediaFoundationPlayer::MEDXDeviceManager> ofMediaFoundationPlayer::sDeviceManager;
19

20
bool ofMediaFoundationPlayer::sBAllowDurationHack = true;
21

22
//----------------------------------------------
23
void ofMediaFoundationPlayer::setDurationHackEnabled(bool ab) {
24
    sBAllowDurationHack = ab;
25
}
26

27
//----------------------------------------------
28
ofMediaFoundationPlayer::MEDXDeviceManager::MEDXDeviceManager() {
29
    gl_handleD3D = nullptr;
30
}
31

32
//----------------------------------------------
33
ofMediaFoundationPlayer::MEDXDeviceManager::~MEDXDeviceManager() {
34
    if (gl_handleD3D != nullptr) {
35
        ofLogVerbose("ofMEDXDeviceManager") << " closing gl handleD3D.";
36
        wglDXCloseDeviceNV(gl_handleD3D);
37
        gl_handleD3D = nullptr;
38
    }
39
    mBUseDX = false;
40
    m_spDXGIManager = nullptr;
41
}
42

43
//----------------------------------------------
44
bool ofMediaFoundationPlayer::MEDXDeviceManager::createDX11Device() {
45
    static const D3D_FEATURE_LEVEL levels[] = {
46
        D3D_FEATURE_LEVEL_11_1,
47
        D3D_FEATURE_LEVEL_11_0,
48
        D3D_FEATURE_LEVEL_10_1,
49
        D3D_FEATURE_LEVEL_10_0,
50
        D3D_FEATURE_LEVEL_9_3,
51
        D3D_FEATURE_LEVEL_9_2,
52
        D3D_FEATURE_LEVEL_9_1
53
    };
54

55
    D3D_FEATURE_LEVEL FeatureLevel;
56
    HRESULT hr = S_OK;
57

58
    mBUseDX = true;
59

60
    hr = D3D11CreateDevice(
61
        nullptr,
62
        D3D_DRIVER_TYPE_HARDWARE,
63
        nullptr,
64
        D3D11_CREATE_DEVICE_VIDEO_SUPPORT | D3D11_CREATE_DEVICE_BGRA_SUPPORT,
65
        levels,
66
        ARRAYSIZE(levels),
67
        D3D11_SDK_VERSION,
68
        &m_spDX11Device,
69
        &FeatureLevel,
70
        &m_spDX11DeviceContext
71
    );
72

73
    if (FAILED(hr)) {
74
        ofLogError("ofMEDXDeviceManager::CreateDX11Device()") << " unable to use hw accel.";
75
        mBUseDX = false;
76
        return mBUseDX;
77
    }
78

79
    ComPtr<ID3D10Multithread> spMultithread;
80
    if (SUCCEEDED(m_spDX11Device.Get()->QueryInterface(IID_PPV_ARGS(&spMultithread)))) {
81
        spMultithread->SetMultithreadProtected(TRUE);
82
    } else {
83
        ofLogError("ofMEDXDeviceManager :: CreateDX11Device") << " unable to set multi thread.";
84
        mBUseDX = false;
85
        return mBUseDX;
86
    }
87

88

89
    hr = MFCreateDXGIDeviceManager(&mResetToken, &m_spDXGIManager);
90
    if (FAILED(hr)) {
91
        ofLogError("ofMEDXDeviceManager :: CreateDX11Device") << " unable to create DXGIDeviceManager.";
92
        mBUseDX = false;
93
        return mBUseDX;
94
    }
95

96
    hr = m_spDXGIManager->ResetDevice(m_spDX11Device.Get(), mResetToken);
97
    if (FAILED(hr)) {
98
        ofLogError("ofMEDXDeviceManager :: CreateDX11Device") << " unable to ResetDevice.";
99
        mBUseDX = false;
100
        return mBUseDX;
101
    }
102

103
    if (mBUseDX) {
104
        if (SUCCEEDED(hr)) {
105
            gl_handleD3D = wglDXOpenDeviceNV(m_spDX11Device.Get());
106
        }
107
    }
108

109
    if (gl_handleD3D == nullptr) {
110
        ofLogError("ofMEDXDeviceManager :: CreateDX11Device") << " error creating GL D3D Handle.";
111
        mBUseDX = false;
112
    }
113

114
    return mBUseDX;
115
}
116

117
class BstrURL {
118
public:
119
    BstrURL(std::string aurl) {
120
        std::wstring ws = std::wstring(aurl.begin(), aurl.end());
121
        assert(!ws.empty());
122
        _bstrStr = SysAllocStringLen(ws.data(), ws.size());
123
    }
124
    ~BstrURL() {
125
        SysReleaseString(_bstrStr);
126
        _bstrStr = nullptr;
127
    }
128

129
    operator BSTR() const { 
130
        return _bstrStr;
131
    }
132
private:
133
    BSTR _bstrStr = nullptr;
134
};
135

136
//----------------------------------------------
137
bool ofMediaFoundationPlayer::METexture::allocate( ofPixelFormat afmt, int aw, int ah) {
138
    if (mOfTex && ((int)mOfTex->getWidth() != aw || (int)mOfTex->getHeight() != ah)) {
139
        mOfTex.reset();
140
    }
141
    if (!mOfTex) {
142
        mOfTex = std::make_shared<ofTexture>();
143
    }
144
    mWidth = aw;
145
    mHeight = ah;
146
    mOfPixFmt = afmt;
147
    //auto glFormat = ofGetGLInternalFormatFromPixelFormat(OF_PIXELS_BGRA);
148
    auto glFormat = ofGetGLInternalFormatFromPixelFormat(afmt);
149
    // make a GL_TEXTURE2D
150
    mOfTex->allocate(mWidth, mHeight, glFormat, false);
151
    return true;
152
}
153

154
//----------------------------------------------
155
bool ofMediaFoundationPlayer::METexture::_swapPixelsFromSrc4ChannelTo3(ofPixels& aDstPix) {
156
    const auto targetPixFormat = aDstPix.getPixelFormat();
157
    const auto srcPixFormat = mSrcPixels.getPixelFormat();
158

159
    bool bNeedsSwap = (srcPixFormat == OF_PIXELS_BGRA && targetPixFormat == OF_PIXELS_RGB);
160
    if (srcPixFormat == OF_PIXELS_RGBA && targetPixFormat == OF_PIXELS_BGR) {
161
        bNeedsSwap = true;
162
    }
163

164
    if (bNeedsSwap) {
165
        auto srcPixels = mSrcPixels.getPixelsIter();
166
        auto dstPixels = aDstPix.getPixelsIter();
167
        auto srcPixel = srcPixels.begin();
168
        auto dstPixel = dstPixels.begin();
169
        auto endPixel = srcPixels.end();
170
        for (; srcPixel != srcPixels.end(); srcPixel++, dstPixel++) {
171
            dstPixel[0] = srcPixel[2];
172
            dstPixel[1] = srcPixel[1];
173
            dstPixel[2] = srcPixel[0];
174
        }
175
    } else {
176
        // straight copy, removing the alpha channel
177
        auto srcPixels = mSrcPixels.getPixelsIter();
178
        auto dstPixels = aDstPix.getPixelsIter();
179
        auto srcPixel = srcPixels.begin();
180
        auto dstPixel = dstPixels.begin();
181
        auto endPixel = srcPixels.end();
182
        for (; srcPixel != srcPixels.end(); srcPixel++, dstPixel++) {
183
            dstPixel[0] = srcPixel[0];
184
            dstPixel[1] = srcPixel[1];
185
            dstPixel[2] = srcPixel[2];
186
        }
187
    }
188
    return true;
189
}
190

191
//----------------------------------------------
192
class SharedDXGLTexture : public ofMediaFoundationPlayer::METexture {
193
public:
194
    SharedDXGLTexture() { mGLDX_Handle = nullptr; }
195
    ~SharedDXGLTexture();
196

197
    bool allocate(ofPixelFormat afmt, int aw, int ah);
198
    bool create(DXGI_FORMAT aDxFormat) override;
199
    bool transferFrame(IMFMediaEngine* aengine) override;
200
    bool isValid() override { return mBValid; }
201
    HANDLE getGLDXHandle() { return mGLDX_Handle; }
202
    ID3D11Texture2D* getDXTexture() { return mDXTex.Get(); }
203

204
    bool draw(ofPixels& apix) override;
205
    bool updatePixels(ofTexture& aSrcTex, ofPixels& apix, ofPixelFormat aTargetPixFormat) override;
206

207
    bool lock();
208
    bool unlock();
209
    bool isLocked();
210

211
protected:
212
    ComPtr<ID3D11Texture2D> mDXTex{ nullptr };
213
    ComPtr<ID3D11Texture2D> stagingTexture{ nullptr };
214
    bool mBValid = false;
215
    HANDLE mGLDX_Handle;
216
    bool mBLocked = false;
217
};
218

219
//----------------------------------------------
220
class WICTextureManager : public ofMediaFoundationPlayer::METexture {
221
public:
222
    bool isValid() override { return mBValid; }
223

224
    bool allocate(ofPixelFormat afmt, int aw, int ah) override;
225
    bool create(DXGI_FORMAT aDxFormat) override;
226

227
    bool transferFrame(IMFMediaEngine* aengine) override;
228
    bool draw(ofPixels& apix) override;
229
    bool updatePixels(ofTexture& aSrcTex, ofPixels& apix, ofPixelFormat aTargetPixFormat) override;
230

231
protected:
232
    Microsoft::WRL::ComPtr<IWICBitmap> mWicBitmap = nullptr;
233
    Microsoft::WRL::ComPtr<IWICImagingFactory> mWicFactory = nullptr;
234
    bool mBValid = false;
235
};
236

237
//----------------------------------------------
238
bool SharedDXGLTexture::allocate(ofPixelFormat afmt, int aw, int ah) {
239
    ofPixelFormat outfmt = OF_PIXELS_BGRA;
240
    if (afmt == OF_PIXELS_RGBA || afmt == OF_PIXELS_RGB) {
241
        outfmt = OF_PIXELS_RGBA;
242
    }
243
    return METexture::allocate(outfmt, aw, ah);
244
}
245

246
//----------------------------------------------
247
bool SharedDXGLTexture::create(DXGI_FORMAT aDxFormat) {
248
    unsigned int tw = static_cast<unsigned int>(getWidth());
249
    unsigned int th = static_cast<unsigned int>(getHeight());
250

251
    D3D11_TEXTURE2D_DESC desc = {};
252
    desc.Width = tw;
253
    desc.Height = th;
254
    desc.MipLevels = 1;
255
    desc.ArraySize = 1;
256
    desc.Format = aDxFormat;
257
    desc.SampleDesc.Count = 1;
258
    desc.SampleDesc.Quality = 0;
259
    desc.BindFlags = D3D11_BIND_RENDER_TARGET;
260
    desc.Usage = D3D11_USAGE_DEFAULT;
261

262
    auto dxMan = ofMediaFoundationPlayer::getDxDeviceManager();
263

264
    if (SUCCEEDED(dxMan->getD11Device()->CreateTexture2D(&desc, nullptr, mDXTex.GetAddressOf()))) {
265
        mGLDX_Handle = wglDXRegisterObjectNV(
266
            dxMan->getGLHandleD3D(), 
267
            mDXTex.Get(),
268
            mOfTex->getTextureData().textureID,
269
            GL_TEXTURE_2D, 
270
            WGL_ACCESS_READ_ONLY_NV);
271

272
        D3D11_TEXTURE2D_DESC desc2;
273
        desc2.Width = desc.Width;
274
        desc2.Height = desc.Height;
275
        desc2.MipLevels = desc.MipLevels;
276
        desc2.ArraySize = desc.ArraySize;
277
        desc2.Format = desc.Format;
278
        desc2.SampleDesc = desc.SampleDesc;
279
        desc2.Usage = D3D11_USAGE_STAGING;
280
        desc2.BindFlags = 0;
281
        desc2.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
282
        desc2.MiscFlags = 0;
283

284
        HRESULT hr = dxMan->getD11Device()->CreateTexture2D(&desc2, nullptr, stagingTexture.GetAddressOf());
285
        if (FAILED(hr)) {
286
            ofLogError("ofMEVideoPlayer :: SharedDXGLTexture :: create") << " Failed to create staging texture";
287
            return false;
288
        }
289

290
        mBValid = (mGLDX_Handle != nullptr);
291
    } else {
292
        ofLogError("SharedDXGLTexture :: createSharedTexture") << " ERROR Creating shared texture.";
293
        mBValid = false;
294
    }
295
    return mBValid;
296
}
297

298
//----------------------------------------------
299
bool SharedDXGLTexture::transferFrame(IMFMediaEngine* aengine) {
300
    if (!mBValid || !mGLDX_Handle) {
301
        return false;
302
    }
303
    RECT targetRect{ 0, 0, mWidth, mHeight };
304
    if ((aengine->TransferVideoFrame(
305
        getDXTexture(),
306
        &mNormalizedVidRect, &targetRect, &bgColor)) == S_OK) {
307
        return true;
308
    }
309
    return false;
310
}
311

312
//----------------------------------------------
313
bool SharedDXGLTexture::lock() {
314
    if (mBLocked) return false;
315
    if (!mBValid) return false;
316
    mBLocked = wglDXLockObjectsNV(ofMediaFoundationPlayer::getDxDeviceManager()->getGLHandleD3D(), 1, &mGLDX_Handle );
317
    return mBLocked;
318
}
319

320
//----------------------------------------------
321
bool SharedDXGLTexture::unlock() {
322
    if (!mBLocked) return false;
323
    if (wglDXUnlockObjectsNV(ofMediaFoundationPlayer::getDxDeviceManager()->getGLHandleD3D(), 1, &mGLDX_Handle )) {
324
        mBLocked = false;
325
        return true;
326
    }
327
    return false;
328
}
329

330
//----------------------------------------------
331
bool SharedDXGLTexture::isLocked() {
332
    return mBLocked;
333
}
334

335
//----------------------------------------------
336
bool SharedDXGLTexture::draw(ofPixels& apix) {
337
    if (lock()) {
338
        mOfTex->draw(0, 0);
339
        unlock();
340
        return true;
341
    }
342
    return false;
343
}
344

345
//----------------------------------------------
346
bool SharedDXGLTexture::updatePixels(ofTexture& aSrcTex, ofPixels& apix, ofPixelFormat aTargetPixFormat) {
347

348
    auto deviceMan = ofMediaFoundationPlayer::getDxDeviceManager();
349
    auto immediateContext = deviceMan->getContext();
350
    ID3D11Texture2D* lDestImage = getDXTexture();
351
    auto d3device = deviceMan->getD11Device();
352

353
    // Copy GPU Resource to CPU
354
    D3D11_TEXTURE2D_DESC desc;
355
    lDestImage->GetDesc(&desc);
356
    D3D11_MAPPED_SUBRESOURCE mapInfo;
357

358
    HRESULT hr = S_OK;
359
    immediateContext->CopyResource(stagingTexture.Get(), lDestImage);
360
    // copy the texture to a staging resource
361
    if (!stagingTexture) {
362
        ofLogError("ofMediaFoundationPlayer :: SharedDXGLTexture :: updatePixels") << " ERROR copying staging texture.";
363
        return false;
364
    }
365

366
    // now, map the staging resource
367
    hr = immediateContext->Map(
368
        stagingTexture.Get(),
369
        0,
370
        D3D11_MAP_READ,
371
        0,
372
        &mapInfo);
373
    if (hr != S_OK) {
374
        ofLogError("ofMediaFoundationPlayer :: SharedDXGLTexture :: updatePixels") << " Failed to map staging texture.";
375
        return false;
376
    }
377
    immediateContext->Unmap(stagingTexture.Get(), 0);
378

379
    if (FAILED(hr)) {
380
        ofLogVerbose("ofMediaFoundationPlayer :: SharedDXGLTexture :: updatePixels") << " unable to map hw dx texture.";
381
        aSrcTex.readToPixels(apix);
382
        return apix.getWidth() > 0;
383
    }
384
    // the mOfPixFmt is always going to be BGRA || RGBA
385
    bool bSetStraightOnPix = (mOfPixFmt == aTargetPixFormat);
386
    if (mOfPixFmt == OF_PIXELS_BGRA && aTargetPixFormat == OF_PIXELS_RGBA) {
387
        bSetStraightOnPix = true;
388
    }
389
    if (mOfPixFmt == OF_PIXELS_RGBA && aTargetPixFormat == OF_PIXELS_BGRA) {
390
        bSetStraightOnPix = true;
391
    }
392
    if (bSetStraightOnPix) {
393
        apix.setFromPixels(reinterpret_cast<unsigned char*>(mapInfo.pData), getWidth(), getHeight(), mOfPixFmt);
394
        if (aTargetPixFormat != mOfPixFmt) {
395
            apix.swapRgb();
396
        }
397
    } else {
398
        mSrcPixels.setFromPixels(reinterpret_cast<unsigned char*>(mapInfo.pData), getWidth(), getHeight(), mOfPixFmt);
399

400
        apix.allocate(mSrcPixels.getWidth(), mSrcPixels.getHeight(), aTargetPixFormat);
401
        _swapPixelsFromSrc4ChannelTo3(apix);
402
    }
403
    return apix.getWidth() > 0 && apix.getHeight() > 0;
404
}
405

406
//----------------------------------------------
407
SharedDXGLTexture::~SharedDXGLTexture() {
408
    // release the handle 
409
    if (mGLDX_Handle != nullptr) {
410
        if (wglGetCurrentContext() != nullptr) {
411
            if (isLocked()) {
412
                unlock();
413
            }
414
            wglDXUnregisterObjectNV(ofMediaFoundationPlayer::getDxDeviceManager()->getGLHandleD3D(), mGLDX_Handle);
415
            mGLDX_Handle = nullptr;
416
        }
417
    }
418
}
419

420
//----------------------------------------------
421
bool WICTextureManager::allocate(ofPixelFormat afmt, int aw, int ah) {
422
    ofLogVerbose("ofMediaFoundationVideoPlayer :: WICTextureManager") << " allocate.";
423
    METexture::allocate(OF_PIXELS_BGRA, aw, ah);
424
    mBValid = false;
425
    HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&mWicFactory));
426
    if (hr == S_OK && mWicFactory) {
427
        mBValid = true;
428
        ofLogVerbose("ofMediaFoundationVideoPlayer :: WICTextureManager") << " created CLSID_WICImagingFactory.";
429
    } else {
430
        ofLogError("ofMediaFoundationVideoPlayer :: WICTextureManager") << " CLSID_WICImagingFactory.";
431
        mWicFactory = nullptr;
432
    }
433
    return mBValid;
434
}
435

436
//----------------------------------------------
437
bool WICTextureManager::create(DXGI_FORMAT aDxFormat) {
438
    
439
    if (mBValid && mWicFactory) {
440
        unsigned int tw = static_cast<unsigned int>(getWidth());
441
        unsigned int th = static_cast<unsigned int>(getHeight());
442

443
        if (!mWicBitmap || mWidth != tw || mHeight != th) {
444
            if (mWicBitmap) {
445
                mWicBitmap->Release();
446
            }
447
            mWidth = tw;
448
            mHeight = th;
449

450
            GUID wicPixFmt = GUID_WICPixelFormat32bppBGRA;
451
            //GUID_WICPixelFormat32bppRGBA
452
            HRESULT hr = mWicFactory->CreateBitmap(tw, th, wicPixFmt, WICBitmapCacheOnDemand,
453
                mWicBitmap.GetAddressOf());
454
            if (hr == S_OK) {
455

456
            } else {
457
                ofLogError("ofMediaFoundationVideoPlayer :: WICTextureManager") << " ERROR CreateBitmap.";
458
                mBValid = false;
459
                mWicBitmap = nullptr;
460
            }
461
        }
462
    }
463

464
    return mBValid;
465
}
466

467
//----------------------------------------------
468
bool WICTextureManager::transferFrame(IMFMediaEngine* aengine) {
469
    if (!mBValid || !mWicBitmap) {
470
        return false;
471
    }
472
    RECT targetRect{ 0, 0, mWidth, mHeight };
473
    if ((aengine->TransferVideoFrame(
474
        mWicBitmap.Get(),
475
        &mNormalizedVidRect, &targetRect, &bgColor)) == S_OK) {
476
        return true;
477
    }
478
    return false;
479
}
480

481
//----------------------------------------------
482
bool WICTextureManager::draw(ofPixels& apix) {
483

484
    ComPtr<IWICBitmapLock> lockedData;
485
    DWORD flags = WICBitmapLockRead;
486
    WICRect srcRect{ 0, 0, mWidth, mHeight };
487

488
    if (FAILED(mWicBitmap->Lock(&srcRect, flags, lockedData.GetAddressOf()))) {
489
        return false;
490
    }
491

492
    UINT stride{ 0 };
493
    if (FAILED(lockedData->GetStride(&stride))) {
494
        return false;
495
    }
496

497
    UINT bufferSize{ 0 };
498
    unsigned char* data{ nullptr };
499
    if (FAILED(lockedData->GetDataPointer(&bufferSize, &data))) {
500
        return false;
501
    }
502

503
    mSrcPixels.setFromAlignedPixels(data, getWidth(), getHeight(), mOfPixFmt, stride);
504
    mOfTex->loadData(apix);
505
    //mOfTex->loadData(data, mWidth, mHeight, GL_BGRA);
506
    mOfTex->draw(0, 0);
507

508
    lockedData->Release();
509

510
    return true;
511
}
512

513
//----------------------------------------------
514
bool WICTextureManager::updatePixels(ofTexture& aSrcTex, ofPixels& apix, ofPixelFormat aTargetPixFormat) {
515
    // always has mOfPixFmt == OF_PIXELS_BGRA
516
    bool bSetStraightOnPix = (mOfPixFmt == aTargetPixFormat);
517
    if (mOfPixFmt == OF_PIXELS_BGRA && aTargetPixFormat == OF_PIXELS_RGBA) {
518
        bSetStraightOnPix = true;
519
    }
520
    if (bSetStraightOnPix) {
521
        apix = mSrcPixels;
522
        if (aTargetPixFormat != mOfPixFmt) {
523
            apix.swapRgb();
524
        }
525
    } else {
526
        // swap around pixels 
527
        apix.allocate(mSrcPixels.getWidth(), mSrcPixels.getHeight(), aTargetPixFormat);
528
        _swapPixelsFromSrc4ChannelTo3(apix);
529
    }
530
    return true;
531
}
532

533
//----------------------------------------------
534
std::string ofMediaFoundationPlayer::MFEventToString(MF_MEDIA_ENGINE_EVENT aevent) {
535
    static std::unordered_map<MF_MEDIA_ENGINE_EVENT, std::string> sMFMessages =
536
    {
537
        { MF_MEDIA_ENGINE_EVENT_LOADSTART, "MF_MEDIA_ENGINE_EVENT_LOADSTART" },
538
            { MF_MEDIA_ENGINE_EVENT_PROGRESS, "MF_MEDIA_ENGINE_EVENT_PROGRESS" },
539
            { MF_MEDIA_ENGINE_EVENT_SUSPEND, "MF_MEDIA_ENGINE_EVENT_SUSPEND" },
540
            { MF_MEDIA_ENGINE_EVENT_ABORT, "MF_MEDIA_ENGINE_EVENT_ABORT" },
541
            { MF_MEDIA_ENGINE_EVENT_ERROR, "MF_MEDIA_ENGINE_EVENT_ERROR" },
542
            { MF_MEDIA_ENGINE_EVENT_EMPTIED, "MF_MEDIA_ENGINE_EVENT_EMPTIED" },
543
            { MF_MEDIA_ENGINE_EVENT_STALLED, "MF_MEDIA_ENGINE_EVENT_STALLED" },
544
            { MF_MEDIA_ENGINE_EVENT_PLAY, "MF_MEDIA_ENGINE_EVENT_PLAY" },
545
            { MF_MEDIA_ENGINE_EVENT_PAUSE, "MF_MEDIA_ENGINE_EVENT_PAUSE" },
546
            { MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA, "MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA" },
547
            { MF_MEDIA_ENGINE_EVENT_LOADEDDATA, "MF_MEDIA_ENGINE_EVENT_LOADEDDATA" },
548
            { MF_MEDIA_ENGINE_EVENT_WAITING, "MF_MEDIA_ENGINE_EVENT_WAITING" },
549
            { MF_MEDIA_ENGINE_EVENT_PLAYING, "MF_MEDIA_ENGINE_EVENT_PLAYING" },
550
            { MF_MEDIA_ENGINE_EVENT_CANPLAY, "MF_MEDIA_ENGINE_EVENT_CANPLAY" },
551
            { MF_MEDIA_ENGINE_EVENT_CANPLAYTHROUGH, "MF_MEDIA_ENGINE_EVENT_CANPLAYTHROUGH" },
552
            { MF_MEDIA_ENGINE_EVENT_SEEKING, "MF_MEDIA_ENGINE_EVENT_SEEKING" },
553
            { MF_MEDIA_ENGINE_EVENT_SEEKED, "MF_MEDIA_ENGINE_EVENT_SEEKED" },
554
            { MF_MEDIA_ENGINE_EVENT_TIMEUPDATE, "MF_MEDIA_ENGINE_EVENT_TIMEUPDATE" },
555
            { MF_MEDIA_ENGINE_EVENT_ENDED, "MF_MEDIA_ENGINE_EVENT_ENDED" },
556
            { MF_MEDIA_ENGINE_EVENT_RATECHANGE, "MF_MEDIA_ENGINE_EVENT_RATECHANGE" },
557
            { MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE, "MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE" },
558
            { MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, "MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE" },
559
            { MF_MEDIA_ENGINE_EVENT_FORMATCHANGE, "MF_MEDIA_ENGINE_EVENT_FORMATCHANGE" },
560
            { MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS, "MF_MEDIA_ENGINE_EVENT_PURGEQUEUEDEVENTS" },
561
            { MF_MEDIA_ENGINE_EVENT_TIMELINE_MARKER, "MF_MEDIA_ENGINE_EVENT_TIMELINE_MARKER" },
562
            { MF_MEDIA_ENGINE_EVENT_BALANCECHANGE, "MF_MEDIA_ENGINE_EVENT_BALANCECHANGE" },
563
            { MF_MEDIA_ENGINE_EVENT_DOWNLOADCOMPLETE, "MF_MEDIA_ENGINE_EVENT_DOWNLOADCOMPLETE" },
564
            { MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED, "MF_MEDIA_ENGINE_EVENT_BUFFERINGSTARTED" },
565
            { MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED, "MF_MEDIA_ENGINE_EVENT_BUFFERINGENDED" },
566
            { MF_MEDIA_ENGINE_EVENT_FRAMESTEPCOMPLETED, "MF_MEDIA_ENGINE_EVENT_FRAMESTEPCOMPLETED" },
567
            { MF_MEDIA_ENGINE_EVENT_NOTIFYSTABLESTATE, "MF_MEDIA_ENGINE_EVENT_NOTIFYSTABLESTATE" },
568
            { MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY, "MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY" },
569
            { MF_MEDIA_ENGINE_EVENT_TRACKSCHANGE, "MF_MEDIA_ENGINE_EVENT_TRACKSCHANGE" },
570
            { MF_MEDIA_ENGINE_EVENT_OPMINFO, "MF_MEDIA_ENGINE_EVENT_OPMINFO" },
571
            { MF_MEDIA_ENGINE_EVENT_RESOURCELOST, "MF_MEDIA_ENGINE_EVENT_RESOURCELOST" },
572
            { MF_MEDIA_ENGINE_EVENT_DELAYLOADEVENT_CHANGED, "MF_MEDIA_ENGINE_EVENT_DELAYLOADEVENT_CHANGED" },
573
            { MF_MEDIA_ENGINE_EVENT_STREAMRENDERINGERROR, "MF_MEDIA_ENGINE_EVENT_STREAMRENDERINGERROR" },
574
            { MF_MEDIA_ENGINE_EVENT_SUPPORTEDRATES_CHANGED, "MF_MEDIA_ENGINE_EVENT_SUPPORTEDRATES_CHANGED" },
575
            { MF_MEDIA_ENGINE_EVENT_AUDIOENDPOINTCHANGE, "MF_MEDIA_ENGINE_EVENT_AUDIOENDPOINTCHANGE" }
576
    };
577

578
    if (sMFMessages.count(aevent) > 0) {
579
        return sMFMessages.at(aevent);
580
    }
581
    return std::to_string(aevent);
582
}
583

584
//----------------------------------------------
585
std::string ofMediaFoundationPlayer::MFErrorToString(MF_MEDIA_ENGINE_ERR aerror) {
586
    static std::unordered_map<MF_MEDIA_ENGINE_ERR, std::string> sMFErrorMessages =
587
    {
588
        {MF_MEDIA_ENGINE_ERR_NOERROR, "MF_MEDIA_ENGINE_ERR_NOERROR" },
589
        {MF_MEDIA_ENGINE_ERR_ABORTED, "MF_MEDIA_ENGINE_ERR_ABORTED"},
590
        {MF_MEDIA_ENGINE_ERR_NETWORK, "MF_MEDIA_ENGINE_ERR_NETWORK"},
591
        {MF_MEDIA_ENGINE_ERR_DECODE, "MF_MEDIA_ENGINE_ERR_DECODE"},
592
        {MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED, "MF_MEDIA_ENGINE_ERR_SRC_NOT_SUPPORTED"},
593
        {MF_MEDIA_ENGINE_ERR_ENCRYPTED, "MF_MEDIA_ENGINE_ERR_ENCRYPTED"}
594
    };
595

596
    if (sMFErrorMessages.count(aerror) > 0) {
597
        return sMFErrorMessages.at(aerror);
598
    }
599

600
    return std::to_string(aerror);
601
}
602

603
//----------------------------------------------
604
ofMediaFoundationPlayer::ofMediaFoundationPlayer() {
605
    //sInitMediaFoundation();
606
    // TODO: this is currently located in ofMediaFoundationSoundPlayer
607
    ofMediaFoundationUtils::InitMediaFoundation();
608
	InitializeCriticalSectionEx(&m_critSec, 0, 0);
609
    mPixFormat = OF_PIXELS_RGB;
610
}
611

612
//----------------------------------------------
613
ofMediaFoundationPlayer::~ofMediaFoundationPlayer() {
614
    close();
615
    ofMediaFoundationUtils::CloseMediaFoundation();
616
    DeleteCriticalSection(&m_critSec);
617
}
618

619
//----------------------------------------------
620
std::shared_ptr<ofMediaFoundationPlayer::MEDXDeviceManager> ofMediaFoundationPlayer::getDxDeviceManager() {
621
    if (!sDeviceManager) {
622
        sDeviceManager = std::make_shared<MEDXDeviceManager>();
623
        sDeviceManager->createDX11Device();
624
    }
625
    return sDeviceManager;
626
}
627

628
//----------------------------------------------
629
bool ofMediaFoundationPlayer::load(std::string name) {
630
    return _load(name, false);
631
}
632

633
//----------------------------------------------
634
void ofMediaFoundationPlayer::loadAsync(std::string name) {
635
    _load(name, true);
636
}
637

638
//----------------------------------------------
639
bool ofMediaFoundationPlayer::_load(std::string name, bool abAsync) {
640
    close();
641

642
    mBLoadAsync = abAsync;
643

644
    bool bStream = false;
645
    bStream = bStream || ofIsStringInString(name, "http://");
646
    bStream = bStream || ofIsStringInString(name, "https://");
647
    bStream = bStream || ofIsStringInString(name, "rtsp://");
648
    bStream = bStream || ofIsStringInString(name, "rtmp://");
649

650
    std::string absPath = name;
651

652
    if (!bStream) {
653
        if (ofFile::doesFileExist(absPath)) {
654
            absPath = ofFilePath::getAbsolutePath(absPath, true);
655
        } else {
656
            ofLogError("ofMediaFoundationPlayer") << " file does not exist! " << absPath;
657
            return false;
658
        }
659
    }
660

661

662
    EnterCriticalSection(&m_critSec);
663

664
    // init device manager if not created
665
    if (isUsingHWAccel()) {
666
        setUsingHWAccel(getDxDeviceManager()->isHWSupported());
667
    }
668

669
    if (isUsingHWAccel()) {
670
        ofLogVerbose("ofMediaFoundationPlayer::load") << " utilizing hardware acceleration.";
671
    } else {
672
        ofLogVerbose("ofMediaFoundationPlayer::load") << " utilizing software decoding.";
673
    }
674

675

676
    ComPtr<IMFMediaEngineClassFactory> spFactory;
677
    ComPtr<IMFAttributes> spAttributes;
678

679
    HRESULT hr = S_OK;
680

681
    hr = CoCreateInstance(CLSID_MFMediaEngineClassFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spFactory));
682

683
    if (FAILED(hr)) {
684
        ofLogError("ofMediaFoundationPlayer::load") << " unable to create Media Engine Class Factory.";
685
    }
686
    if (SUCCEEDED(hr)) {
687
        mEventProcessor = std::make_shared<ofMEEventProcessor>();
688
        mEventProcessor->setCB(this);
689
        hr = MFCreateAttributes(&spAttributes, 1);
690
        if (FAILED(hr)) {
691
            ofLogError("ofMediaFoundationPlayer::load") << " unable to MFCreateAttributes.";
692
        }
693
    }
694

695
    if (SUCCEEDED(hr)) {
696
        if (isUsingHWAccel()) {
697
            hr = spAttributes->SetUnknown(MF_MEDIA_ENGINE_DXGI_MANAGER, (IUnknown*)getDxDeviceManager()->getDXGIManagerPtr());
698
            if (FAILED(hr)) {
699
                ofLogError("ofMediaFoundationPlayer::load") << " unable to set device Manager.";
700
            }
701
        }
702
    }
703

704
    if (SUCCEEDED(hr)) {
705
        hr = spAttributes->SetUnknown(MF_MEDIA_ENGINE_CALLBACK, (IUnknown*)mEventProcessor.get());
706
        if (FAILED(hr)) {
707
            ofLogError("ofMediaFoundationPlayer::load") << " unable to set media engine callback.";
708
        }
709
    }
710

711
    if (SUCCEEDED(hr)) {
712
        hr = spAttributes->SetUINT32(MF_MEDIA_ENGINE_VIDEO_OUTPUT_FORMAT, m_d3dFormat);
713
        if (FAILED(hr)) {
714
            ofLogError("ofMediaFoundationPlayer::load") << " unable to set Video Output Format.";
715
        }
716
    }
717

718
    if (SUCCEEDED(hr)) {
719
        //const DWORD flags = MF_MEDIA_ENGINE_WAITFORSTABLE_STATE;
720
        const DWORD flags = MF_MEDIA_ENGINE_REAL_TIME_MODE;
721
        hr = spFactory->CreateInstance(flags, spAttributes.Get(), &m_spMediaEngine);
722
        if (FAILED(hr)) {
723
            ofLogError("ofMediaFoundationPlayer::load") << " unable to create media engine.";
724
        }
725
    }
726

727
    m_spMediaEngine->SetAutoPlay(FALSE);
728

729
    // now lets make a BSTR 
730
    m_spMediaEngine->SetSource(BstrURL(absPath));
731

732
    hr = m_spMediaEngine->Load();
733

734
    //mBLoaded = (hr == S_OK);
735

736
    if (hr == S_OK) {
737
        HRESULT hr2 = m_spMediaEngine.Get()->QueryInterface(__uuidof(IMFMediaEngine), (void**)&m_spEngineEx);
738
        if (FAILED(hr2)) {
739
            ofLogError("ofMediaFoundationPlayer::load") << " unable to create media engine ex.";
740
        }
741
    }
742

743
    LeaveCriticalSection(&m_critSec);
744

745
    if (hr != S_OK) {
746
        close();
747
    }
748

749
    if (!mBLoadAsync) {
750
        if (hr == S_OK) {
751
            mBIsDoneAtomic.store(false);
752
            mBIsClosedAtomic.store(false);
753

754
            std::mutex lock;
755
            std::unique_lock lk{ lock };
756
            mWaitCondition.wait(lk, [&] { return mBIsDoneAtomic.load() || mBIsClosedAtomic.load();  });
757
        }
758
    }
759

760
    //mBLoaded = SUCCEEDED(hr);
761

762
    return (hr == S_OK);
763
}
764

765

766

767
//----------------------------------------------
768
void ofMediaFoundationPlayer::close() {
769

770
    mBIsClosedAtomic.store(true);
771
    mBIsDoneAtomic.store(false);
772
    mWaitCondition.notify_all();
773

774
    EnterCriticalSection(&m_critSec);
775

776
    if (m_spMediaEngine) {
777
        ofMediaFoundationUtils::CallAsyncBlocking(
778
            [&] { m_spMediaEngine->Shutdown(); }
779
        );
780
    }
781

782
    m_spMediaEngine = nullptr;
783

784
    // clear out the events 
785
    {
786
        std::unique_lock<std::mutex> lk(mMutexEvents);
787
        if (!mEventsQueue.empty()) {
788
            std::queue<DWORD> tempty;
789
            std::swap(mEventsQueue, tempty);
790
        }
791
    }
792

793
    mTargetSeekPercent = -1.0f;
794
    mBLoaded = false;
795
    mBNewFrame = false;
796
    mDuration = 0.f;
797
    mWidth = 0.f;
798
    mHeight = 0.f;
799
    mBReady = false;
800
    mBDone = false;
801
    mBPlaying = false;
802
    mBCanSeek = false;
803
    mFramerate = 1.f / 30.f;
804
    mEstimatedNumFrames = 1;
805
    mBUpdatePixels = false;
806

807
    if (mMeTexture) {
808
        mMeTexture.reset();
809
    }
810

811
    if (mEventProcessor) {
812
        mEventProcessor.reset();
813
    }
814

815
    mFbo.clear();
816

817
    LeaveCriticalSection(&m_critSec);
818

819
}
820

821
//----------------------------------------------
822
bool ofMediaFoundationPlayer::isInitialized() const {
823
    return mBReady;
824
}
825

826
//----------------------------------------------
827
void ofMediaFoundationPlayer::OnMediaEngineEvent(DWORD aEvent, DWORD_PTR param1, DWORD param2) {
828
    if (aEvent == MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA) {
829
        if (!mBLoadAsync) {
830
            mBIsDoneAtomic.store(true);
831
            mWaitCondition.notify_one();
832
        }
833
        mBLoaded = true;
834
    } else if (aEvent == MF_MEDIA_ENGINE_EVENT_ERROR) {
835
        // not sure if we should handle this here
836
        ofLogVerbose("engine event: ofMediaFoundationPlayer") << " ERRROR";
837
        // clear out the mutex so that we no longer wait and the close event can be fired
838
        if (!mBLoadAsync) {
839
            mBIsDoneAtomic.store(false);
840
            mBIsClosedAtomic.store(true);
841
            mWaitCondition.notify_one();
842
        }
843
    }
844
    // lets not overload the events, query similar with isFrameNew()
845
    if (aEvent != MF_MEDIA_ENGINE_EVENT_TIMEUPDATE) {
846
        std::unique_lock<std::mutex> tt(mMutexEvents);
847
        mEventsQueue.push(aEvent);
848
    }
849

850

851
}
852

853
//----------------------------------------------
854
void ofMediaFoundationPlayer::update() {
855
    mBNewFrame = false;
856
    mBDone = false;
857
    if (mBLoaded && hasVideo() ) {
858
        LONGLONG time;
859
        if(m_spMediaEngine->OnVideoStreamTick(&time) == S_OK) {
860
            if (mMeTexture && mMeTexture->isValid()) {
861
                if ( mMeTexture->transferFrame(m_spMediaEngine.Get())) {
862
                    ofPushStyle(); {
863
                        ofSetColor(255);
864

865
                        bool bValidDraw = false;
866
                        mFbo.begin(); {
867
                            bValidDraw = mMeTexture->draw(mPixels);
868
                        } mFbo.end();
869

870
                        if (bValidDraw) {
871
                            mCopyTex = mFbo.getTexture();
872
                            if (mBUpdatePixels) {
873
                                mMeTexture->updatePixels(mCopyTex, mPixels,mPixFormat);
874
                            }
875
                            mBNewFrame = true;
876
                        }
877
                    } ofPopStyle();
878
                }
879
            }
880
        }
881
    }
882

883
    if (m_spMediaEngine) {
884
        if (!mBLoaded) {
885
            mTargetSeekPercent = -1.f;
886
        }
887
        if (mTargetSeekPercent > -0.5f && isInitialized()) {
888
            setPosition(mTargetSeekPercent);
889
        }
890
    }
891

892
    if (ofMediaFoundationPlayer::sBAllowDurationHack && m_spMediaEngine) {
893
        if (mBLoaded) {
894
            //not sure why the GetDuration() method returns inaccurate values,
895
            // but this will update the duration if the current time is larger
896
            double ctime = m_spMediaEngine->GetCurrentTime();
897
            if (ctime > mDuration) {
898
                mDuration = ctime;
899
                if (mFramerate > 0.0) {
900
                    mEstimatedNumFrames = mDuration / (1.f / mFramerate);
901
                }
902
            }
903
        }
904
        if (mBNewFrame) {
905
            if (mFramerate > 0.0) {
906
                mEstimatedNumFrames = mDuration / (1.f / mFramerate);
907
            }
908
        }
909
    }
910

911
    unsigned int mMaxEventsToProcess = 1000;
912
    unsigned int numEventsProcessed = 0;
913
    // now lets update the events in the queue
914
    bool bHasEvent = true;
915
    DWORD tevent;
916
    while (bHasEvent && (numEventsProcessed < mMaxEventsToProcess) ) { 
917
        bHasEvent = false;
918
        {
919
            std::unique_lock<std::mutex> lk(mMutexEvents);
920
            if (!mEventsQueue.empty()) {
921
                tevent = mEventsQueue.front();
922
                mEventsQueue.pop();
923
                bHasEvent = true;
924
            }
925
        }
926
        if (bHasEvent) {
927
            // handle the event //
928
            handleMEEvent(tevent);
929
            numEventsProcessed++;
930
        }
931
    }
932
}
933

934
//----------------------------------------------
935
bool ofMediaFoundationPlayer::isFrameNew() const {
936
    return mBNewFrame;
937
}
938

939
//----------------------------------------------
940
void ofMediaFoundationPlayer::play() {
941
    if (m_spMediaEngine) {
942
        if (mBDone) {
943
            setPosition(0.f);   
944
        }
945
        m_spMediaEngine->Play();
946
        mBDone = false;
947
    }
948
}
949

950
//----------------------------------------------
951
void ofMediaFoundationPlayer::stop() {
952
    if (m_spMediaEngine) {
953
        if (isPlaying()) {
954
            setPosition(0.f);
955
            setPaused(true);
956
            mBDone = false;
957
        }
958
    }
959
}
960

961
//----------------------------------------------
962
void ofMediaFoundationPlayer::setPaused(bool bPause) {
963
    if (m_spMediaEngine) {
964
        if (bPause) {
965
            m_spMediaEngine->Pause();
966
            mBPlaying = false;
967
        } else {
968
            play();
969
        }
970
    }
971
}
972

973
//----------------------------------------------
974
bool ofMediaFoundationPlayer::isLoaded() const {
975
    return mBLoaded;
976
}
977

978
//----------------------------------------------
979
bool ofMediaFoundationPlayer::isPlaying() const {
980
    return mBPlaying;
981
}
982

983
//----------------------------------------------
984
float ofMediaFoundationPlayer::getWidth() const {
985
    return mWidth;
986
}
987

988
//----------------------------------------------
989
float ofMediaFoundationPlayer::getHeight() const {
990
    return mHeight;
991
}
992

993
//----------------------------------------------
994
ofTexture* ofMediaFoundationPlayer::getTexturePtr() {
995
    return &mCopyTex;
996
}
997

998
//----------------------------------------------
999
bool ofMediaFoundationPlayer::isPaused() const {
1000
    if (m_spMediaEngine) {
1001
        return m_spMediaEngine->IsPaused();
1002
    }
1003
    return false;
1004
}
1005

1006
//----------------------------------------------
1007
void ofMediaFoundationPlayer::setPosition(float pct) {
1008
    if (m_spMediaEngine) {
1009
        if (!mBCanSeek) {
1010
            ofLogError("ofMediaFoundationPlayer :: setPosition") << " seeking is not supported.";
1011
            return;
1012
        }
1013

1014
        if (mDuration > 0.0 && isInitialized() && pct >= 0.f && pct <= 1.0f) {
1015
            // does not like when we are seeking //
1016
            double ttime = static_cast<double>(pct) * mDuration;
1017
            if (ttime >= mDuration) {
1018
                ttime = mDuration;
1019
            }
1020
            if (ttime < 0.0) {
1021
                ttime = 0.0;
1022
            }
1023
            if (!m_spMediaEngine->IsSeeking()) {
1024
                if (m_spEngineEx) {
1025
                    // MF_MEDIA_ENGINE_SEEK_MODE_APPROXIMATE
1026
                    m_spEngineEx->SetCurrentTimeEx(ttime, MF_MEDIA_ENGINE_SEEK_MODE_NORMAL);
1027
                } else if (m_spMediaEngine) {
1028
                    m_spMediaEngine->SetCurrentTime(ttime);
1029
                }
1030
                mTargetSeekPercent = -1.f;
1031
                //callAsync([&] {m_spMediaEngine->SetCurrentTime(ttime); });
1032
            } else {
1033
                mTargetSeekPercent = pct;
1034
            }
1035
        }
1036
    }
1037
}
1038

1039
//----------------------------------------------
1040
void ofMediaFoundationPlayer::setSpeed(float speed) {
1041
    if (m_spMediaEngine && m_spEngineEx) {
1042
        if (m_spEngineEx->IsPlaybackRateSupported(static_cast<double>(speed))) {
1043
            HRESULT hr = m_spMediaEngine->SetPlaybackRate(static_cast<double>(speed));
1044
            if (hr != S_OK) {
1045
                ofLogVerbose("ofMediaFoundationPlayer :: setSpeed : Unable to set speed to ") << speed << ".";
1046
            }
1047
        }
1048
    }
1049
}
1050

1051
//----------------------------------------------
1052
void ofMediaFoundationPlayer::setVolume(float volume) {
1053
    if (m_spMediaEngine) {
1054
        ofMediaFoundationUtils::CallAsyncBlocking(
1055
            [&] {m_spMediaEngine->SetVolume(static_cast<double>(volume)); 
1056
        });
1057
    }
1058
}
1059

1060
//----------------------------------------------
1061
void ofMediaFoundationPlayer::setFrame(int frame) {
1062
    setPosition((float)frame / (float)getTotalNumFrames());
1063
}
1064

1065
//----------------------------------------------
1066
int ofMediaFoundationPlayer::getCurrentFrame() const {
1067
    return getPosition() * mEstimatedNumFrames;
1068
}
1069

1070
//----------------------------------------------
1071
int ofMediaFoundationPlayer::getTotalNumFrames() const {
1072
    return mEstimatedNumFrames;
1073
}
1074

1075
//----------------------------------------------
1076
void ofMediaFoundationPlayer::setLoopState(ofLoopType state) {
1077
    if (state == OF_LOOP_NONE || state == OF_LOOP_NORMAL ) {
1078
        if (m_spMediaEngine) {
1079
            BOOL loop = (state == OF_LOOP_NORMAL) ? TRUE : FALSE;
1080
            m_spMediaEngine->SetLoop( loop );
1081
        }
1082
        mLoopType = state;
1083
    } else {
1084
        ofLogError("ofMediaFoundationPlayer") << " cannot set loop of type palindrome.";
1085
    }
1086
}
1087

1088
//----------------------------------------------
1089
ofLoopType ofMediaFoundationPlayer::getLoopState() const {
1090
    return mLoopType;
1091
}
1092

1093
//----------------------------------------------
1094
float ofMediaFoundationPlayer::getPosition() const {
1095
    if (m_spMediaEngine && mDuration > 0.0 ) {
1096
        //return static_cast<float>(m_spMediaEngine->GetCurrentTime()) / mDuration;
1097
        const double ctime = m_spMediaEngine->GetCurrentTime();
1098
        if (ctime > mDuration) {
1099
            mDuration = ctime;
1100
        }
1101
        return (ctime) / mDuration;
1102
    }
1103
    return 0.f;
1104
}
1105

1106
//----------------------------------------------
1107
float ofMediaFoundationPlayer::getSpeed() const {
1108
    if (m_spMediaEngine) {
1109
        return static_cast<float>(m_spMediaEngine->GetPlaybackRate());
1110
    }
1111
    return 1.f;
1112
}
1113

1114
//----------------------------------------------
1115
float ofMediaFoundationPlayer::getDuration() const {
1116
    return mDuration;
1117
}
1118

1119
//----------------------------------------------
1120
bool ofMediaFoundationPlayer::getIsMovieDone() const {
1121
    return mBDone;
1122
}
1123

1124
//----------------------------------------------
1125
bool ofMediaFoundationPlayer::hasAudio() {
1126
    if (m_spMediaEngine) {
1127
        return m_spMediaEngine->HasAudio();
1128
    }
1129
    return false;
1130
}
1131

1132
//----------------------------------------------
1133
bool ofMediaFoundationPlayer::hasVideo() {
1134
    if (m_spMediaEngine) {
1135
        return m_spMediaEngine->HasVideo();
1136
    }
1137
    return false;
1138
}
1139

1140
//----------------------------------------------
1141
void ofMediaFoundationPlayer::firstFrame() {
1142
    setPosition(0.0f);
1143
}
1144

1145
//----------------------------------------------
1146
void ofMediaFoundationPlayer::nextFrame() {
1147
    if (m_spEngineEx) {
1148
        m_spEngineEx->FrameStep(TRUE);
1149
    }
1150
}
1151

1152
//----------------------------------------------
1153
void ofMediaFoundationPlayer::previousFrame() {
1154
    if (m_spEngineEx) {
1155
        m_spEngineEx->FrameStep(FALSE);
1156
    }
1157
}
1158

1159
//----------------------------------------------
1160
bool ofMediaFoundationPlayer::setPixelFormat(ofPixelFormat pixelFormat) {
1161
    if (pixelFormat == OF_PIXELS_BGRA || pixelFormat == OF_PIXELS_BGR ) {
1162
        m_d3dFormat = DXGI_FORMAT_B8G8R8A8_UNORM;
1163
    } else if(pixelFormat == OF_PIXELS_RGBA || pixelFormat == OF_PIXELS_RGB ) {
1164
        m_d3dFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
1165
    }
1166

1167
    switch (pixelFormat) {
1168
    case OF_PIXELS_RGB:
1169
    case OF_PIXELS_BGR:
1170
    case OF_PIXELS_BGRA:
1171
    case OF_PIXELS_RGBA:
1172
        mPixFormat = pixelFormat;
1173
        return true;
1174
    default:
1175
        return false;
1176
    }
1177
    return false;
1178
}
1179

1180
//----------------------------------------------
1181
ofPixelFormat ofMediaFoundationPlayer::getPixelFormat() const {
1182
    return mPixFormat;
1183
}
1184

1185
//----------------------------------------------
1186
ofPixels& ofMediaFoundationPlayer::getPixels() {
1187
    if (!mBUpdatePixels && mFbo.isAllocated()) {
1188
        mFbo.readToPixels(mPixels);
1189
    }
1190
    mBUpdatePixels = true;
1191
    return mPixels;
1192
}
1193

1194
//----------------------------------------------
1195
const ofPixels& ofMediaFoundationPlayer::getPixels() const {
1196
    mBUpdatePixels = true;
1197
    return mPixels;
1198
}
1199

1200
//----------------------------------------------
1201
void ofMediaFoundationPlayer::handleMEEvent(DWORD aevent) {
1202
    if (aevent != MF_MEDIA_ENGINE_EVENT_TIMEUPDATE) {
1203
        ofLogVerbose("ofMediaFoundationPlayer") << MFEventToString(static_cast<MF_MEDIA_ENGINE_EVENT>(aevent));
1204
    }
1205

1206
    switch (aevent) {
1207
        case MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA:
1208
        {
1209
            //mDuration = static_cast<float>(m_spMediaEngine->GetDuration());
1210
            updateDuration();
1211
            if (mDuration != mDuration || mDuration == std::numeric_limits<float>::infinity()) {
1212
                mDuration = 0.f;
1213
            } else {
1214
                DWORD caps = 0;
1215
                if (m_spEngineEx) {
1216
                    m_spEngineEx->GetResourceCharacteristics(&caps);
1217
                    mBCanSeek = (caps & MFMEDIASOURCE_CAN_SEEK) > 0;
1218
                }
1219
            }
1220
            mBDone = false;
1221
            mWidth = 0.f;
1222
            mHeight = 0.f;
1223
            DWORD w, h;
1224
            if (SUCCEEDED(m_spMediaEngine->GetNativeVideoSize(&w, &h))) {
1225
                mWidth = w;
1226
                mHeight = h;
1227

1228
                if (mMeTexture) {
1229
                    if (mMeTexture->getWidth() != mWidth || mMeTexture->getHeight() != mHeight) {
1230
                        mMeTexture.reset();
1231
                        mFbo.clear();
1232
                    }
1233
                }
1234

1235
                if (!mMeTexture) {
1236
                    if (isUsingHWAccel()) {
1237
                        ofLogVerbose(" ofMediaFoundationPlayer::handleMEEvent") << " creating a shared texture that is hw supported.";
1238
                        mMeTexture = std::make_shared<SharedDXGLTexture>();
1239
                    } else {
1240
                        ofLogVerbose(" ofMediaFoundationPlayer::handleMEEvent") << " creating a WIC Texture manager.";
1241
                        mMeTexture = std::make_shared<WICTextureManager>();
1242
                    }
1243
                    mMeTexture->allocate(mPixFormat, getWidth(), getHeight());
1244
                    mMeTexture->create(m_d3dFormat);
1245

1246
                    ofFbo::Settings fsettings;
1247
                    fsettings.internalformat = ofGetGLInternalFormatFromPixelFormat(mPixFormat);
1248
                    fsettings.useDepth = false;
1249
                    fsettings.useStencil = false;
1250
                    fsettings.width = mWidth;
1251
                    fsettings.height = mHeight;
1252
                    fsettings.numSamples = 0;
1253
                    mFbo.allocate(fsettings);
1254
                    mFbo.begin(); {
1255
                        ofClear(0, 0, 0, 255);
1256
                    } mFbo.end();
1257
                    mCopyTex = mFbo.getTexture();
1258
                }
1259
            }
1260
            // in case this was called before load //
1261
            setLoopState(getLoopState());
1262
            //mBReady = true;
1263
            mBLoaded = true;
1264
            break;
1265
        }
1266
        case MF_MEDIA_ENGINE_EVENT_LOADEDDATA:
1267
        {
1268
            //IMFMediaEngineEx::GetStreamAttribute
1269
            //HRESULT GetStreamAttribute(
1270
            //    [in]  DWORD       dwStreamIndex,
1271
            //    [in]  REFGUID     guidMFAttribute,
1272
            //    [out] PROPVARIANT * pvValue
1273
            //);
1274
            // MF_MT_FRAME_RATE
1275
            DWORD nstreams;
1276
            
1277
            if (m_spEngineEx && SUCCEEDED(m_spEngineEx->GetNumberOfStreams(&nstreams)) ) {
1278
                if (nstreams > 0) {
1279

1280
                    //MF_MT_FRAME_RATE                {UINT64 (HI32(Numerator),LO32(Denominator))}
1281
                    {
1282
                        PROPVARIANT pvar;
1283
                        HRESULT hr = m_spEngineEx->GetStreamAttribute(0, MF_MT_FRAME_RATE, &pvar);
1284
                        if (hr == S_OK) {
1285
                            auto numerator = pvar.hVal.HighPart / pvar.hVal.LowPart;
1286
                            auto denom = pvar.uhVal.HighPart / pvar.uhVal.LowPart;
1287
                            mFramerate = (static_cast<float>(pvar.hVal.HighPart) / static_cast<float>(pvar.hVal.LowPart));
1288
                        } else {
1289
                            mFramerate = 1.f / 30.f;
1290
                        }
1291
                        PropVariantClear(&pvar);
1292
                    }
1293
                    updateDuration();
1294
                }
1295
            }
1296

1297
            //mBReady = true;
1298
            break;
1299
        }
1300
        case MF_MEDIA_ENGINE_EVENT_CANPLAY:
1301
        {
1302
            // Start the Playback
1303
            //play();
1304
            //stop();
1305
            break;
1306
        }
1307
        case MF_MEDIA_ENGINE_EVENT_PLAY:
1308
        {
1309
            mBPlaying = true;
1310
            break;
1311
        }
1312
        case MF_MEDIA_ENGINE_EVENT_PAUSE:
1313
        {
1314
            mBPlaying = false;
1315
            break;
1316
        }
1317
        case MF_MEDIA_ENGINE_EVENT_ENDED:
1318
        {
1319
            mBDone = true;
1320
            break;
1321
        }
1322
        case MF_MEDIA_ENGINE_EVENT_TIMEUPDATE:
1323
        {
1324
            break;
1325
        }
1326
        case MF_MEDIA_ENGINE_EVENT_SEEKING:
1327
        {
1328
            mTimeStartedSeek = m_spMediaEngine->GetCurrentTime();
1329
            break;
1330
        }
1331
        case MF_MEDIA_ENGINE_EVENT_SEEKED:
1332
        {
1333
            auto ctime = m_spMediaEngine->GetCurrentTime();
1334
            // looping videos don't fire off an ended event, so try here
1335
            if (ctime < 0.1 && (ctime - mTimeStartedSeek < 0.05)) {
1336
                mBDone = true;
1337
            }
1338

1339
            break;
1340
        }
1341
        case MF_MEDIA_ENGINE_EVENT_ERROR:
1342
        {
1343
            if (m_spMediaEngine) {
1344
                ComPtr<IMFMediaError> error;
1345
                if (m_spMediaEngine->GetError(&error) == S_OK) {
1346
                    USHORT errorCode = error->GetErrorCode();
1347
                    MF_MEDIA_ENGINE_ERR meError = static_cast<MF_MEDIA_ENGINE_ERR>(errorCode);
1348
                    ofLogError("ofMediaFoundationPlayer") << MFErrorToString(meError);
1349
                    ofNotifyEvent(MFErrorEvent, meError, this);
1350
                    close();
1351
                }
1352
            }
1353
            break;
1354

1355
        }
1356
        case MF_MEDIA_ENGINE_EVENT_DURATIONCHANGE:
1357
        {
1358
            updateDuration();
1359
            break;
1360
        }
1361
        case MF_MEDIA_ENGINE_EVENT_FIRSTFRAMEREADY:
1362
        {
1363
            mBReady = true;
1364
        }
1365
    }
1366
    MF_MEDIA_ENGINE_EVENT mfEvent = static_cast<MF_MEDIA_ENGINE_EVENT>(aevent);
1367
    ofNotifyEvent(MFEngineEvent, mfEvent, this);
1368
    
1369
}
1370

1371
//-----------------------------------------
1372
void ofMediaFoundationPlayer::updateDuration() {
1373
    if (m_spMediaEngine) {
1374
        mDuration = (m_spMediaEngine->GetDuration());
1375
        ofLogVerbose("ofMediaFoundationPlayer") << " update duration: " << mDuration;
1376
        if (mDuration != mDuration || mDuration == std::numeric_limits<double>::infinity()) {
1377
            mDuration = 0.0;
1378
        }
1379
        if (mDuration > 0.0 && mFramerate > 0.f) {
1380
            mEstimatedNumFrames = mDuration / (1.f / mFramerate);
1381
        } else {
1382
            mEstimatedNumFrames = 1;
1383
        }
1384
    }
1385
}
1386

1387

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

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

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

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