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:
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user