MarcGBeauchamp

Is it possible to play a protected media file in a topology using the tee node. I modified the ProtectedPlayback sample and I get MF_E_TOPO_UNSUPPORTED error after setting the topology.

Thanks!



Re: Media Foundation Development Protected Content (PMP) and tee node

Becky Weiss - MSFT

I'm going to assume you're talking about video streams here. If I'm right about that, then what's preventing this from working actually has nothing to do with the PMP; it has to do with the requirements of the EVR.

I addressed this a couple months ago on this forum. I'll paste what I said below, but here's the whole thread: http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=749493&SiteID=1

P.S. Because of the way the MF pipeline works, whenever you have a sink that's D3D-aware (like the EVR, but probably not like your "mySink"), the node directly upstream from that sink (EVR) needs to be an MFT. Furthermore, this MFT needs to _not_ provide its own samples -- i.e. the MFT_OUTPUT_STREAM_PROVIDES_SAMPLES flag needs to be off for this MFT.

The brief version of the rationale for this requirement is that you need some component to move the data from the system memory buffers that come out of the Media Source to the D3D surface samples that the EVR needs its buffer in.

So something like this works great:

Src --> DecoderMFT --> EVR

... Because decoder MFTs generally do not provide their own output samples.

Something like this will not work as-is:

UncompressedVideoSrc --> EVR

To make it work, all you'd need to do is write a simple "copier" MFT that just copies data from input to output and do this:

UncompressedVideoSrc --> CopierMFT --> EVR

... and that would work.

Another topology that will not work is the one you have:

Src --> DecoderMFT --> Tee --> EVR

--> SomeOtherSink

... because tee nodes don't copy samples. But something like this would work:

Src --> DecoderMFT --> Tee --> CopierMFT --> EVR

--> SomeOtherSink

Hope that helps

Becky






Re: Media Foundation Development Protected Content (PMP) and tee node

MarcGBeauchamp

Actually I was talking about a protected WMA file. It plays fine in WMP11 and in the ProtectedSample as is. But not when I insert a tee node into the topology.

Thanks





Re: Media Foundation Development Protected Content (PMP) and tee node

hashbrown

Hi Marc,

It could be that your Tee Node is not signed, and thus it cannot be placed in the Protected Process, and so topology creation fails.





Re: Media Foundation Development Protected Content (PMP) and tee node

Becky Weiss - MSFT

Tee nodes don't actually need any PMP-signing (I'm assuming you're using MFCreateTopologyNode to create the node, and if you're not, you should be), since the code all belongs to MF; none of it is your code.

The fact that you're trying but failing to get a topology with a tee node and audio working in the PMP is surprising... Does your topology work without the PMP (i.e. regular in-proc playback, like most of the playback samples do) And what exactly does the topology look like






Re: Media Foundation Development Protected Content (PMP) and tee node

MarcGBeauchamp

1) I am creating the tee node with MFCreateTopology node.

2) The topology works if the audio source is not a protected file (mp3). It fails when I play my WMA song. It does NOT fail when playing this WMA song without the tee node in the topology.

3) Very simple topology: Source->Tee->SAR

Marc





Re: Media Foundation Development Protected Content (PMP) and tee node

Becky Weiss - MSFT

All right, now that's kind of sounding like a bug. Give me a few days to try it out on my end, and I'll let you know what's up. Your tee node has only one output... Do I have that right






Re: Media Foundation Development Protected Content (PMP) and tee node

MarcGBeauchamp

yes, just one output.

It should be easy to recreate the situation. Here's the relacement AddBranchToPartialTopology:

HRESULT CPlayer::AddBranchToPartialTopology(IMFTopology *pTopology, IMFPresentationDescriptor *pSourcePD, DWORD iStream)

{

TRACE((L"CPlayer::AddBranchToPartialTopology"));

assert(pTopology != NULL);

IMFStreamDescriptor* pSourceSD = NULL;

IMFTopologyNode* pSourceNode = NULL;

IMFTopologyNode* pOutputNode = NULL;

BOOL fSelected = FALSE;

HRESULT hr = S_OK;

// Get the stream descriptor for this stream.

hr = pSourcePD->GetStreamDescriptorByIndex(iStream, &fSelected, &pSourceSD);

LOG_IF_FAILED(L"IMFPresentationDescriptor::GetStreamDescriptorByIndex", hr);

if (SUCCEEDED(hr))

{

// Create the topology branch only if the stream is selected.

// Otherwise, do nothing.

if (fSelected)

{

// Create a source node for this stream.

hr = CreateSourceStreamNode(pSourcePD, pSourceSD, &pSourceNode);

hr = pTopology->AddNode(pSourceNode);

IMFTopologyNode* pTeeNode = NULL;

MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &pTeeNode);

pTopology->AddNode(pTeeNode);

pSourceNode->ConnectOutput(0, pTeeNode, 0);

// Create the output node for the renderer.

if (SUCCEEDED(hr))

{

hr = CreateOutputNode(pSourceSD, &pOutputNode);

}

// Add both nodes to the topology.

/*

if (SUCCEEDED(hr))

{

hr = pTopology->AddNode(pSourceNode);

LOG_IF_FAILED(L"IMFTopology::AddNode", hr);

}

*/

if (SUCCEEDED(hr))

{

hr = pTopology->AddNode(pOutputNode);

LOG_IF_FAILED(L"IMFTopology::AddNode", hr);

}

// Connect the source node to the output node.

if (SUCCEEDED(hr))

{

//hr = pSourceNode->ConnectOutput(0, pOutputNode, 0);

hr = pTeeNode->ConnectOutput(0, pOutputNode, 0);

LOG_IF_FAILED(L"IMFTopologyNode::ConnectOutput", hr);

}

}

}

// Clean up.

SAFE_RELEASE(pTeeNode);

SAFE_RELEASE(pSourceSD);

SAFE_RELEASE(pSourceNode);

SAFE_RELEASE(pOutputNode);

return hr;

}





Re: Media Foundation Development Protected Content (PMP) and tee node

Becky Weiss - MSFT

Bug confirmed, unfortunately.

Because of some implementation details inside the MF topology loader, it'll fail to obtain and insert the decrypter if the source node is immediately followed by a tee node. I'll make a note of the issue so that we can fix it.

Meanwhile, as a workaround, you could so something like insert a dummy MFT between the source and the tee:

Src --> DummyMFT --> Tee --> Whatever

So long as this dummy MFT requires that its media type be MFMediaType_Audio (i.e. it rejects MFMediaType_Protected) as an input type, the MF topoloader will get the hint and insert the decrypter.

Thanks much for reporting this issue, Marc...

Becky






Re: Media Foundation Development Protected Content (PMP) and tee node

MarcGBeauchamp

Can I just co-create an IMFTransform or do I have to build my own IMFTransform and register it

If so, anything else special about this dummy MFT   What category does it have to be (MFT_CATEGORY_AUDIO_DECODER, MFT_CATEGORY_AUDIO_EFFECT) or does it even matter

If I understand correctly, that dummy MFT will be discarded from the topology since it does not accept MFMediaType_Protected

Marc





Re: Media Foundation Development Protected Content (PMP) and tee node

Becky Weiss - MSFT

I inadvertently omitted a detail here, and also I thought of a possibly easier option.

If you're going to go the dummy MFT route, you'll need this dummy MFT to require that its input type be uncompressed audio (cf video). The reason you have to require uncompressed media is to force the topoloader to insert a decrypter _and_ a decoder between the source node and your MFT node. At least in the case of WMDRM-protected content, the decrypter needs to be directly upstream of the decoder, since we set up a secure authenticated channel between those two nodes (IMFSampleProtection is the interface involved on these MFTs). The MFT should set outputtype == inputtype and then simply copy or pass samples through, whichever is easier for you. For the category, I'd recommend calling it an EFFECT, though since you'll be inserting it in the topology by hand, there's no reason to MFTRegister it.

As another option which might be less work, you could also insert the decrypter and decoder by hand yourself, between the source node and the tee node. Because topology-loading occurs in the mfpmp process, you accomplish this by implementing IMFTopoLoader in a CoClass and setting the MF_SESSION_TOPOLOADER attribute to your TopoLoader's CLSID in MFCreatePMPMediaSession's pConfiguration attributes store. For your TopoLoader implementation, you'll get your Src --> Tee --> Sink partial topology as the pInputTopo argument, to which your code should add a decrypter and a decoder between Src and Tee. To get the decrypter, you need to get the source's IMFInputTrustAuthority and call GetDecrypter. To get the decoder, you'll want to get it from MFTEnum.

Your TopoLoader implementation would then just create the MF topology loader (MFCreateTopoLoader) and call its Load() to do the rest of the work. The topology you pass it will look like Src --> Decrypter --> Decoder --> Tee --> Sink.

I haven't personally tried either of these approaches, but I believe they'll work.