microsoft / media-foundation

Repository for Windows Media Foundation related tools and samples
MIT License
144 stars 31 forks source link

MediaEngineDCompWin32Sample for PlayReady content // AV in IMFContentDecryptionModuleSession::GenerateRequest call #61

Open roman380 opened 11 months ago

roman380 commented 11 months ago

I am looking into extending MediaEngineDCompWin32Sample application to enable it play PlayReady content. Given that playback asset in #60 is fixed the application starts the playback.

I would like to enable it to also play PlayReady protected content (and then playready content coming from our source).

To define a simple initial case I would like to play asset from MediaEngineEMEUWPSample which also plays well there. Apparently there should be some PMP reference involved, discussion about something related I found in #37.

There is a discussion about IMFContentDecryptionModule::SetPMPHostApp for which I would need IMFContentDecryptionModule and it seems I have a problem even getting this. The initialization copy from MediaEngineEMEUWPSample starting from IMFContentDecryptionModuleFactory4::CreateContentDecryptionModuleFactory gives me type supported, and then fails at IMFContentDecryptionModuleAccess->CreateContentDecryptionModule so that I can't even have a CDM pointer:

0xC00D36BA : 'The object does not support the specified service.'.

Even though the arguments are the asme as in UWP EME

        // This is equivalent to the following Javascript EME call:
        // Navigator.requestMediaKeySystemAccess("com.microsoft.playready.recommendation", [{ initDataTypes: ['cenc'], persistentState: 'optional', distinctiveIdentifier: 'required'])

From the MF Media Engine end, execution reaches Windows::Media::Protection::IMediaProtectionManager::Properties() call where I seem to need to pass properties obtained from CDM and I don't have it.

If I use C++/WinRT defined MediaProtectionManager instead with properties borrowed from UWP PlayReady sample, this does not work either because, as I assume, the application is outside of UWP and requires additional steps.

Could you please give some guidance how to connect the pieces together?

roman380 commented 11 months ago

With the help of #37 I could really pass further.

So, first of all, there is indeed an exception

Exception thrown at 0x00007FFD211CCF19 (KernelBase.dll) in CompositionPlayback.exe: WinRT originate error - 0xC00D36BA : 'The object does not support the specified service.'.

taking place in IMFContentDecryptionModuleAccess::CreateContentDecryptionModule call:

    KernelBase.dll!00007ffd211ccf19()   Unknown
    combase.dll!SendReport(HRESULT error, unsigned int cchMax, const wchar_t * message, unsigned short pSid, void * pExceptionObject, IUnknown *) Line 433  C++
    combase.dll!RoOriginateErrorW(HRESULT error, unsigned int cchMax, const wchar_t * message) Line 569 C++
    Windows.Media.dll!Windows::Media::Report(HRESULT hr) Line 22    C++
    Windows.Media.dll!Windows::Media::Protection::MediaProtectionPMPServerImpl::GetService(const _GUID & guidService, const _GUID & riid, void * * ppvObject) Line 182  C++
    Windows.Media.Protection.PlayReady.dll!00007ffcdf29d1e2()   Unknown
    Windows.Media.Protection.PlayReady.dll!00007ffcdf29dbbc()   Unknown
    Windows.Media.Protection.PlayReady.dll!00007ffcdf2a02b0()   Unknown
    Windows.Media.Protection.PlayReady.dll!00007ffcdf29d68a()   Unknown
    Windows.Media.Protection.PlayReady.dll!00007ffcdf29b24c()   Unknown
    Windows.Media.Protection.PlayReady.dll!00007ffcdf261293()   Unknown
    Windows.Media.Protection.PlayReady.dll!00007ffcdf263419()   Unknown
>   CompositionPlayback.exe!MediaEngineNotify::CreateContentDecryptionModule(const wil::com_ptr_t<IMFMediaEngineClassFactory,wil::err_exception_policy> & ClassFactory) Line 509    C++
    CompositionPlayback.exe!MediaEngineNotify::Initialize::__l2::<lambda>(IMFAsyncResult * AsynResult) Line 549 C++

But you can skip it and you obtain the COM pointer.

Then I am seeing a call from CMD to create a client space object Windows.Media.Protection.PlayReady.PRRemoteObjectFactory, and it succeeds.

Then I am seeing a few calls to winrt::Windows::Media::Protection::IMediaProtectionManager::Properties(), where I try to follow logic of UWP EME sample (also spotted in Chromium). I do see the property set is populated with values Windows.Media.Protection.ConstrictionActive, Windows.Media.Protection.GraphicsTrustStatus but then player fails fast, where UWP EME player takes time to wait for exchange of messages with PlayReady server.

This is some progress, so I will follow up then when I give up.

roman380 commented 11 months ago

Following steps of MediaEngineEMEUWPSample along with establishing connection to PMP server, the application reaches IMFContentDecryptionModuleSession::GenerateRequest call. CDM session is created. it's GetSessionId succeeds returning empty string givin ghte impression that the pointer is generally valid.

The arguments to the call GenerateRequest are exactly the same as in the MediaEngineEMEUWPSample: "cenc" and 852 bytes of WRMHEADER.

There is an exception inside GenerateRequest:

Exception thrown at 0x00007FFC3284B4FA (Windows.Media.Protection.PlayReady.dll) in CompositionPlayback.exe: 0xC0000005: Access violation reading location 0x0000000000000000.

IMFContentDecryptionModuleSessionCallbacks::KeyMessage is never called.

MFTrace gives this:

CompositionPlayback.txt

What makes it also different from UWP app is that there is another internal exception at some point

Exception thrown at 0x00007FFD211CCF19 (KernelBase.dll) in CompositionPlayback.exe: 0x000006A6: The binding handle is invalid.

Its call stack suggests its MF related

KernelBase.dll!RaiseException()
rpcrt4.dll!RpcpRaiseException()
rpcrt4.dll!RpcRaiseException()
rpcrt4.dll!GenericHandleMgr()
rpcrt4.dll!ExplicitBindHandleMgr()
rpcrt4.dll!NdrpClientCall3()
rpcrt4.dll!NdrClientCall3()
wwapi.dll!WwanOpenHandle()
WWanAPI.dll!CNamespaceController::PopulateNSElements()
WWanAPI.dll!CNamespaceController::Init()
WWanAPI.dll!CNamespaceController::GetInstance()
WWanAPI.dll!CMbnInterfaceManager::GetInterfaces()
mf.dll!00007ffd030ed3db()
mf.dll!00007ffd030ea67b()
mf.dll!00007ffd030e72cb()
mf.dll!00007ffd030e70b7()

It happens at the time of IMFContentDecryptionModuleAccess::CreateContentDecryptionModule call even though eventually it succeeds and gives the IMFContentDecryptionModule pointer.


The above was in Windows 10 system, and in another Windows 11 system the behavior is basically the same with the one exception: GenerateMessage retuns without AV, however returns 0x8004C3E8 failure.

Given the discussion about app container in a neigboring topic, is there maybe a requirement to run in app container outside UWP? I gave it a quick try and I see that container has a small impact: giving it no capbility for network connections, I see GenerateRequest giving WININET_E_NAME_NOT_RESOLVED. However once I grant that, the behavior is similar to the previous paragraph: AV crash or 0x8004C3E8.

roman380 commented 11 months ago

If this could help, I can share a standalone small Win32 app whcih produced 0x8004C3E8 or memory AV as described above.

cjrog commented 11 months ago

If you are able to provide the team with a way to reproduce the error you are seeing, that would greatly help us in identifying the issue.

roman380 commented 11 months ago

If you are able to provide the team with a way to reproduce the error you are seeing, that would greatly help us in identifying the issue.

Thanks for your attempt. I posted the reproducer into branch at fork here https://github.com/microsoft/media-foundation/pull/62, I also added review/comments to point to the problem in question and reproduction steps.