WMF: correctly handle media with multiple streams.

Only use the default streams and make sure only one stream of each kind
(audio/video) is added to the topology.

Change-Id: Ied37174fa722068b4cd1b5f91b60e0cef5c1d7b3
Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
This commit is contained in:
Yoann Lopes
2015-11-07 18:07:34 +01:00
parent 8ed8f33c18
commit 2b7c617e09
2 changed files with 90 additions and 75 deletions

View File

@@ -266,6 +266,25 @@ void MFPlayerSession::handleMediaSourceReady()
} }
} }
MFPlayerSession::MediaType MFPlayerSession::getStreamType(IMFStreamDescriptor *stream) const
{
if (!stream)
return Unknown;
IMFMediaTypeHandler *typeHandler = NULL;
if (SUCCEEDED(stream->GetMediaTypeHandler(&typeHandler))) {
GUID guidMajorType;
if (SUCCEEDED(typeHandler->GetMajorType(&guidMajorType))) {
if (guidMajorType == MFMediaType_Audio)
return Audio;
else if (guidMajorType == MFMediaType_Video)
return Video;
}
}
return Unknown;
}
void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentationDescriptor *sourcePD) void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentationDescriptor *sourcePD)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
@@ -294,45 +313,58 @@ void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentat
for (DWORD i = 0; i < cSourceStreams; i++) for (DWORD i = 0; i < cSourceStreams; i++)
{ {
BOOL fSelected = FALSE; BOOL fSelected = FALSE;
bool streamAdded = false;
IMFStreamDescriptor *streamDesc = NULL; IMFStreamDescriptor *streamDesc = NULL;
HRESULT hr = sourcePD->GetStreamDescriptorByIndex(i, &fSelected, &streamDesc); HRESULT hr = sourcePD->GetStreamDescriptorByIndex(i, &fSelected, &streamDesc);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
MediaType mediaType = Unknown; // The media might have multiple audio and video streams,
IMFTopologyNode *sourceNode = addSourceNode(topology, source, sourcePD, streamDesc); // only use one of each kind, and only if it is selected by default.
if (sourceNode) { MediaType mediaType = getStreamType(streamDesc);
IMFTopologyNode *outputNode = addOutputNode(streamDesc, mediaType, topology, 0); if (mediaType != Unknown
if (outputNode) { && ((m_mediaTypes & mediaType) == 0) // Check if this type isn't already added
bool connected = false; && fSelected) {
if (mediaType == Audio) {
if (!m_audioSampleGrabberNode)
connected = setupAudioSampleGrabber(topology, sourceNode, outputNode);
} else if (mediaType == Video && outputNodeId == -1) {
// Remember video output node ID.
outputNode->GetTopoNodeID(&outputNodeId);
}
if (!connected) IMFTopologyNode *sourceNode = addSourceNode(topology, source, sourcePD, streamDesc);
hr = sourceNode->ConnectOutput(0, outputNode, 0); if (sourceNode) {
if (FAILED(hr)) { IMFTopologyNode *outputNode = addOutputNode(mediaType, topology, 0);
emit error(QMediaPlayer::FormatError, tr("Unable to play any stream."), false); if (outputNode) {
} bool connected = false;
else { if (mediaType == Audio) {
succeededCount++; if (!m_audioSampleGrabberNode)
m_mediaTypes |= mediaType; connected = setupAudioSampleGrabber(topology, sourceNode, outputNode);
switch (mediaType) { } else if (mediaType == Video && outputNodeId == -1) {
case Audio: // Remember video output node ID.
emit audioAvailable(); outputNode->GetTopoNodeID(&outputNodeId);
break;
case Video:
emit videoAvailable();
break;
} }
if (!connected)
hr = sourceNode->ConnectOutput(0, outputNode, 0);
if (FAILED(hr)) {
emit error(QMediaPlayer::FormatError, tr("Unable to play any stream."), false);
} else {
streamAdded = true;
succeededCount++;
m_mediaTypes |= mediaType;
switch (mediaType) {
case Audio:
emit audioAvailable();
break;
case Video:
emit videoAvailable();
break;
}
}
outputNode->Release();
} }
outputNode->Release(); sourceNode->Release();
} }
sourceNode->Release();
} }
if (fSelected && !streamAdded)
sourcePD->DeselectStream(i);
streamDesc->Release(); streamDesc->Release();
} }
} }
@@ -377,56 +409,38 @@ IMFTopologyNode* MFPlayerSession::addSourceNode(IMFTopology* topology, IMFMediaS
return NULL; return NULL;
} }
IMFTopologyNode* MFPlayerSession::addOutputNode(IMFStreamDescriptor *streamDesc, MediaType& mediaType, IMFTopology* topology, DWORD sinkID) IMFTopologyNode* MFPlayerSession::addOutputNode(MediaType mediaType, IMFTopology* topology, DWORD sinkID)
{ {
IMFTopologyNode *node = NULL; IMFTopologyNode *node = NULL;
HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node); if (FAILED(MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node)))
if (FAILED(hr))
return NULL; return NULL;
node->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
mediaType = Unknown; IMFActivate *activate = NULL;
IMFMediaTypeHandler *handler = NULL; if (mediaType == Audio) {
hr = streamDesc->GetMediaTypeHandler(&handler); activate = m_playerService->audioEndpointControl()->createActivate();
if (SUCCEEDED(hr)) { } else if (mediaType == Video) {
GUID guidMajorType; if (m_playerService->videoRendererControl()) {
hr = handler->GetMajorType(&guidMajorType); activate = m_playerService->videoRendererControl()->createActivate();
if (SUCCEEDED(hr)) { } else if (m_playerService->videoWindowControl()) {
IMFActivate *activate = NULL; activate = m_playerService->videoWindowControl()->createActivate();
if (MFMediaType_Audio == guidMajorType) { } else {
mediaType = Audio; qWarning() << "no videoWindowControl or videoRendererControl, unable to add output node for video data";
activate = m_playerService->audioEndpointControl()->createActivate();
} else if (MFMediaType_Video == guidMajorType) {
mediaType = Video;
if (m_playerService->videoRendererControl()) {
activate = m_playerService->videoRendererControl()->createActivate();
} else if (m_playerService->videoWindowControl()) {
activate = m_playerService->videoWindowControl()->createActivate();
} else {
qWarning() << "no videoWindowControl or videoRendererControl, unable to add output node for video data";
}
} else {
// Unknown stream type.
emit error(QMediaPlayer::FormatError, tr("Unknown stream type."), false);
}
if (activate) {
hr = node->SetObject(activate);
if (SUCCEEDED(hr)) {
hr = node->SetUINT32(MF_TOPONODE_STREAMID, sinkID);
if (SUCCEEDED(hr)) {
if (SUCCEEDED(topology->AddNode(node))) {
handler->Release();
return node;
}
}
}
}
} }
handler->Release(); } else {
// Unknown stream type.
emit error(QMediaPlayer::FormatError, tr("Unknown stream type."), false);
} }
node->Release();
return NULL; if (!activate
|| FAILED(node->SetObject(activate))
|| FAILED(node->SetUINT32(MF_TOPONODE_STREAMID, sinkID))
|| FAILED(node->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE))
|| FAILED(topology->AddNode(node))) {
node->Release();
node = NULL;
}
return node;
} }
bool MFPlayerSession::addAudioSampleGrabberNode(IMFTopology *topology) bool MFPlayerSession::addAudioSampleGrabberNode(IMFTopology *topology)

View File

@@ -215,9 +215,10 @@ private:
void createSession(); void createSession();
void setupPlaybackTopology(IMFMediaSource *source, IMFPresentationDescriptor *sourcePD); void setupPlaybackTopology(IMFMediaSource *source, IMFPresentationDescriptor *sourcePD);
MediaType getStreamType(IMFStreamDescriptor *stream) const;
IMFTopologyNode* addSourceNode(IMFTopology* topology, IMFMediaSource* source, IMFTopologyNode* addSourceNode(IMFTopology* topology, IMFMediaSource* source,
IMFPresentationDescriptor* presentationDesc, IMFStreamDescriptor *streamDesc); IMFPresentationDescriptor* presentationDesc, IMFStreamDescriptor *streamDesc);
IMFTopologyNode* addOutputNode(IMFStreamDescriptor *streamDesc, MediaType& mediaType, IMFTopology* topology, DWORD sinkID); IMFTopologyNode* addOutputNode(MediaType mediaType, IMFTopology* topology, DWORD sinkID);
bool addAudioSampleGrabberNode(IMFTopology* topology); bool addAudioSampleGrabberNode(IMFTopology* topology);
bool setupAudioSampleGrabber(IMFTopology *topology, IMFTopologyNode *sourceNode, IMFTopologyNode *outputNode); bool setupAudioSampleGrabber(IMFTopology *topology, IMFTopologyNode *sourceNode, IMFTopologyNode *outputNode);