summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndré de la Rocha <andre.rocha@qt.io>2021-07-18 04:02:38 +0200
committerAndré de la Rocha <andre.rocha@qt.io>2021-07-27 14:06:06 +0200
commitcb488cf23f8967260e2bba36d43d1b5e8ebb49cc (patch)
treeaf5acabdb7ce424665d5d9aaad1cfdafaaf8dc58
parent7054093fdb8ae9c56fd6488be71af2c5cc4e0c4e (diff)
Add support for multiple audio tracks to Windows player backend
Change-Id: I342536e89469a6127d8136b8d6cea563c66518bf Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--examples/multimediawidgets/player/player.cpp30
-rw-r--r--examples/multimediawidgets/player/player.h1
-rw-r--r--src/multimedia/platform/windows/player/mfplayercontrol.cpp26
-rw-r--r--src/multimedia/platform/windows/player/mfplayercontrol_p.h6
-rw-r--r--src/multimedia/platform/windows/player/mfplayersession.cpp287
-rw-r--r--src/multimedia/platform/windows/player/mfplayersession_p.h20
6 files changed, 303 insertions, 67 deletions
diff --git a/examples/multimediawidgets/player/player.cpp b/examples/multimediawidgets/player/player.cpp
index 3005f2e4f..d616fd813 100644
--- a/examples/multimediawidgets/player/player.cpp
+++ b/examples/multimediawidgets/player/player.cpp
@@ -337,6 +337,26 @@ void Player::metaDataChanged()
}
}
+QString Player::trackName(const QMediaMetaData &metaData, int index)
+{
+ QString name;
+ QString title = metaData.stringValue(QMediaMetaData::Title);
+ QLocale::Language lang = metaData.value(QMediaMetaData::Language).value<QLocale::Language>();
+
+ if (title.isEmpty()) {
+ if (lang == QLocale::Language::AnyLanguage)
+ name = tr("Track %1").arg(index+1);
+ else
+ name = QLocale::languageToString(lang);
+ } else {
+ if (lang == QLocale::Language::AnyLanguage)
+ name = title;
+ else
+ name = QString("%1 - [%2]").arg(title).arg(QLocale::languageToString(lang));
+ }
+ return name;
+}
+
void Player::tracksChanged()
{
m_audioTracks->clear();
@@ -345,19 +365,19 @@ void Player::tracksChanged()
const auto audioTracks = m_player->audioTracks();
for (int i = 0; i < audioTracks.size(); ++i)
- m_audioTracks->addItem(audioTracks.at(i).stringValue(QMediaMetaData::Language), i);
+ m_audioTracks->addItem(trackName(audioTracks.at(i), i), i);
m_audioTracks->setCurrentIndex(m_player->activeAudioTrack());
const auto videoTracks = m_player->videoTracks();
for (int i = 0; i < videoTracks.size(); ++i)
- m_videoTracks->addItem(videoTracks.at(i).stringValue(QMediaMetaData::Language), i);
+ m_videoTracks->addItem(trackName(videoTracks.at(i), i), i);
m_videoTracks->setCurrentIndex(m_player->activeVideoTrack());
m_subtitleTracks->addItem(QString::fromUtf8("No subtitles"), -1);
const auto subtitleTracks = m_player->subtitleTracks();
for (int i = 0; i < subtitleTracks.size(); ++i)
- m_subtitleTracks->addItem(subtitleTracks.at(i).stringValue(QMediaMetaData::Language), i);
- m_subtitleTracks->setCurrentIndex(m_player->activeSubtitleTrack());
+ m_subtitleTracks->addItem(trackName(subtitleTracks.at(i), i), i);
+ m_subtitleTracks->setCurrentIndex(m_player->activeSubtitleTrack() + 1);
}
void Player::previousClicked()
@@ -469,7 +489,7 @@ void Player::selectAudioStream()
void Player::selectVideoStream()
{
- int stream = m_audioTracks->currentData().toInt();
+ int stream = m_videoTracks->currentData().toInt();
m_player->setActiveVideoTrack(stream);
}
diff --git a/examples/multimediawidgets/player/player.h b/examples/multimediawidgets/player/player.h
index cba34d973..0be2282f8 100644
--- a/examples/multimediawidgets/player/player.h
+++ b/examples/multimediawidgets/player/player.h
@@ -118,6 +118,7 @@ private:
void setStatusInfo(const QString &info);
void handleCursor(QMediaPlayer::MediaStatus status);
void updateDurationInfo(qint64 currentInfo);
+ QString trackName(const QMediaMetaData &metaData, int index);
QMediaPlayer *m_player = nullptr;
QAudioOutput *m_audioOutput = nullptr;
diff --git a/src/multimedia/platform/windows/player/mfplayercontrol.cpp b/src/multimedia/platform/windows/player/mfplayercontrol.cpp
index 90b6de66f..b114e3264 100644
--- a/src/multimedia/platform/windows/player/mfplayercontrol.cpp
+++ b/src/multimedia/platform/windows/player/mfplayercontrol.cpp
@@ -175,6 +175,11 @@ void MFPlayerControl::handleStatusChanged()
refreshState();
}
+void MFPlayerControl::handleTracksChanged()
+{
+ tracksChanged();
+}
+
void MFPlayerControl::handleVideoAvailable()
{
if (m_videoAvailable)
@@ -300,3 +305,24 @@ void MFPlayerControl::handleError(QMediaPlayer::Error errorCode, const QString&
stop();
emit error(int(errorCode), errorString);
}
+
+void MFPlayerControl::setActiveTrack(TrackType type, int index)
+{
+ m_session->setActiveTrack(type, index);
+}
+
+int MFPlayerControl::activeTrack(TrackType type)
+{
+ return m_session->activeTrack(type);
+}
+
+int MFPlayerControl::trackCount(TrackType type)
+{
+ return m_session->trackCount(type);
+}
+
+QMediaMetaData MFPlayerControl::trackMetaData(TrackType type, int trackNumber)
+{
+ return m_session->trackMetaData(type, trackNumber);
+}
+
diff --git a/src/multimedia/platform/windows/player/mfplayercontrol_p.h b/src/multimedia/platform/windows/player/mfplayercontrol_p.h
index 995181626..e8467ab8d 100644
--- a/src/multimedia/platform/windows/player/mfplayercontrol_p.h
+++ b/src/multimedia/platform/windows/player/mfplayercontrol_p.h
@@ -103,7 +103,13 @@ public:
void setVideoSink(QVideoSink *sink) override;
+ void setActiveTrack(TrackType type, int index) override;
+ int activeTrack(TrackType type) override;
+ int trackCount(TrackType type) override;
+ QMediaMetaData trackMetaData(TrackType type, int trackNumber) override;
+
void handleStatusChanged();
+ void handleTracksChanged();
void handleVideoAvailable();
void handleAudioAvailable();
void handleDurationUpdate(qint64 duration);
diff --git a/src/multimedia/platform/windows/player/mfplayersession.cpp b/src/multimedia/platform/windows/player/mfplayersession.cpp
index 619f7b17a..3d01050da 100644
--- a/src/multimedia/platform/windows/player/mfplayersession.cpp
+++ b/src/multimedia/platform/windows/player/mfplayersession.cpp
@@ -239,6 +239,7 @@ void MFPlayerSession::handleMediaSourceReady()
//convert from 100 nanosecond to milisecond
emit durationUpdate(qint64(m_duration / 10000));
setupPlaybackTopology(mediaSource, sourcePD);
+ tracksChanged();
sourcePD->Release();
} else {
changeStatus(QMediaPlayer::InvalidMedia);
@@ -246,26 +247,49 @@ void MFPlayerSession::handleMediaSourceReady()
}
}
-MFPlayerSession::MediaType MFPlayerSession::getStreamType(IMFStreamDescriptor *stream) const
+bool MFPlayerSession::getStreamInfo(IMFStreamDescriptor *stream,
+ MFPlayerSession::MediaType *type,
+ QString *name,
+ QString *language) const
{
- if (!stream)
- return Unknown;
-
- struct SafeRelease {
- IMFMediaTypeHandler *ptr = nullptr;
- ~SafeRelease() { if (ptr) ptr->Release(); }
- } typeHandler;
- if (SUCCEEDED(stream->GetMediaTypeHandler(&typeHandler.ptr))) {
+ if (!stream || !type || !name || !language)
+ return false;
+
+ *type = Unknown;
+ *name = QString();
+ *language = QString();
+
+ IMFMediaTypeHandler *typeHandler = nullptr;
+
+ if (SUCCEEDED(stream->GetMediaTypeHandler(&typeHandler))) {
+
+ UINT32 len = 0;
+ if (SUCCEEDED(stream->GetStringLength(MF_SD_STREAM_NAME, &len)) && len > 0) {
+ WCHAR *wstr = new WCHAR[len+1];
+ if (SUCCEEDED(stream->GetString(MF_SD_STREAM_NAME, wstr, len+1, &len))) {
+ *name = QString::fromUtf16(reinterpret_cast<const char16_t *>(wstr));
+ }
+ delete []wstr;
+ }
+ if (SUCCEEDED(stream->GetStringLength(MF_SD_LANGUAGE, &len)) && len > 0) {
+ WCHAR *wstr = new WCHAR[len+1];
+ if (SUCCEEDED(stream->GetString(MF_SD_LANGUAGE, wstr, len+1, &len))) {
+ *language = QString::fromUtf16(reinterpret_cast<const char16_t *>(wstr));
+ }
+ delete []wstr;
+ }
+
GUID guidMajorType;
- if (SUCCEEDED(typeHandler.ptr->GetMajorType(&guidMajorType))) {
+ if (SUCCEEDED(typeHandler->GetMajorType(&guidMajorType))) {
if (guidMajorType == MFMediaType_Audio)
- return Audio;
+ *type = Audio;
else if (guidMajorType == MFMediaType_Video)
- return Video;
+ *type = Video;
}
+ typeHandler->Release();
}
- return Unknown;
+ return *type != Unknown;
}
void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentationDescriptor *sourcePD)
@@ -288,64 +312,76 @@ void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentat
return;
}
- // Remember output node id for a first video stream
- TOPOID outputNodeId = -1;
-
// For each stream, create the topology nodes and add them to the topology.
DWORD succeededCount = 0;
- for (DWORD i = 0; i < cSourceStreams; i++)
- {
- BOOL fSelected = FALSE;
+ for (DWORD i = 0; i < cSourceStreams; i++) {
+ BOOL selected = FALSE;
bool streamAdded = false;
IMFStreamDescriptor *streamDesc = NULL;
- HRESULT hr = sourcePD->GetStreamDescriptorByIndex(i, &fSelected, &streamDesc);
+ HRESULT hr = sourcePD->GetStreamDescriptorByIndex(i, &selected, &streamDesc);
if (SUCCEEDED(hr)) {
// The media might have multiple audio and video streams,
// only use one of each kind, and only if it is selected by default.
- MediaType mediaType = getStreamType(streamDesc);
- if (mediaType != Unknown
- && ((m_mediaTypes & mediaType) == 0) // Check if this type isn't already added
- && fSelected) {
-
- IMFTopologyNode *sourceNode = addSourceNode(topology, source, sourcePD, streamDesc);
- if (sourceNode) {
- IMFTopologyNode *outputNode = addOutputNode(mediaType, topology, 0);
- if (outputNode) {
- bool connected = false;
- 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)
- 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;
+ MediaType mediaType = Unknown;
+ QString streamName;
+ QString streamLanguage;
+
+ if (getStreamInfo(streamDesc, &mediaType, &streamName, &streamLanguage)) {
+
+ QPlatformMediaPlayer::TrackType trackType = (mediaType == Audio) ?
+ QPlatformMediaPlayer::AudioStream : QPlatformMediaPlayer::VideoStream;
+
+ QLocale::Language lang = streamLanguage.isEmpty() ?
+ QLocale::Language::AnyLanguage : QLocale(streamLanguage).language();
+
+ QMediaMetaData metaData;
+ metaData.insert(QMediaMetaData::Title, streamName);
+ metaData.insert(QMediaMetaData::Language, lang);
+
+ m_trackInfo[trackType].metaData.append(metaData);
+ m_trackInfo[trackType].nativeIndexes.append(i);
+
+ if (((m_mediaTypes & mediaType) == 0) && selected) { // Check if this type isn't already added
+ IMFTopologyNode *sourceNode = addSourceNode(topology, source, sourcePD, streamDesc);
+ if (sourceNode) {
+ IMFTopologyNode *outputNode = addOutputNode(mediaType, topology, 0);
+ if (outputNode) {
+ bool connected = false;
+ if (mediaType == Audio) {
+ if (!m_audioSampleGrabberNode)
+ connected = setupAudioSampleGrabber(topology, sourceNode, outputNode);
}
+ sourceNode->GetTopoNodeID(&m_trackInfo[trackType].sourceNodeId);
+ outputNode->GetTopoNodeID(&m_trackInfo[trackType].outputNodeId);
+
+ if (!connected)
+ hr = sourceNode->ConnectOutput(0, outputNode, 0);
+
+ if (FAILED(hr)) {
+ emit error(QMediaPlayer::FormatError, tr("Unable to play any stream."), false);
+ } else {
+ m_trackInfo[trackType].currentIndex = m_trackInfo[trackType].nativeIndexes.count() - 1;
+ 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)
+ if (selected && !streamAdded)
sourcePD->DeselectStream(i);
streamDesc->Release();
@@ -356,12 +392,13 @@ void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentat
changeStatus(QMediaPlayer::InvalidMedia);
emit error(QMediaPlayer::ResourceError, tr("Unable to play."), true);
} else {
- if (outputNodeId != -1) {
- topology = insertMFT(topology, outputNodeId);
- }
+ if (m_trackInfo[QPlatformMediaPlayer::VideoStream].outputNodeId != -1)
+ topology = insertMFT(topology, m_trackInfo[QPlatformMediaPlayer::VideoStream].outputNodeId);
hr = m_session->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
- if (FAILED(hr)) {
+ if (SUCCEEDED(hr)) {
+ m_updatingTopology = true;
+ } else {
changeStatus(QMediaPlayer::InvalidMedia);
emit error(QMediaPlayer::ResourceError, tr("Failed to set topology."), true);
}
@@ -982,6 +1019,7 @@ void MFPlayerSession::stop(bool immediate)
scrub(false);
if (SUCCEEDED(m_session->Stop())) {
+
m_state.setCommand(CmdStop);
m_pendingState = CmdPending;
if (m_status != QMediaPlayer::EndOfMedia) {
@@ -1011,6 +1049,12 @@ void MFPlayerSession::start()
if (m_scrubbing)
scrub(false);
+ if (m_restorePosition >= 0) {
+ m_position = m_restorePosition;
+ if (!m_updatingTopology)
+ m_restorePosition = -1;
+ }
+
PROPVARIANT varStart;
InitPropVariantFromInt64(m_position, &varStart);
@@ -1586,6 +1630,7 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
updatePendingCommands(CmdStop);
break;
case MESessionPaused:
+ m_position = position() * 10000;
updatePendingCommands(CmdPause);
break;
case MEReconnectStart:
@@ -1690,6 +1735,9 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
if (SUCCEEDED(MFGetService(m_session, MR_STREAM_VOLUME_SERVICE, IID_PPV_ARGS(&m_volumeControl))))
setVolumeInternal(m_muted ? 0 : m_volume);
+
+ m_updatingTopology = false;
+ stop();
}
}
}
@@ -1772,6 +1820,14 @@ void MFPlayerSession::clear()
m_request.command = CmdNone;
m_request.prevCmd = CmdNone;
+ for (int i = 0; i < QPlatformMediaPlayer::NTrackTypes; ++i) {
+ m_trackInfo[i].metaData.clear();
+ m_trackInfo[i].nativeIndexes.clear();
+ m_trackInfo[i].currentIndex = -1;
+ m_trackInfo[i].sourceNodeId = -1;
+ m_trackInfo[i].outputNodeId = -1;
+ }
+
if (!m_metaData.isEmpty()) {
m_metaData.clear();
emit metaDataChanged();
@@ -1826,3 +1882,112 @@ void MFPlayerSession::setVideoSink(QVideoSink *sink)
{
m_videoRendererControl->setSink(sink);
}
+
+void MFPlayerSession::setActiveTrack(QPlatformMediaPlayer::TrackType type, int index)
+{
+ if (!m_session)
+ return;
+
+ // Only audio track selection is currently supported.
+ if (type != QPlatformMediaPlayer::AudioStream)
+ return;
+
+ const auto &nativeIndexes = m_trackInfo[type].nativeIndexes;
+
+ if (index < -1 || index >= nativeIndexes.count() || index == m_trackInfo[type].currentIndex)
+ return;
+
+ IMFTopology *topology = nullptr;
+
+ if (SUCCEEDED(m_session->GetFullTopology(MFSESSION_GETFULLTOPOLOGY_CURRENT, 0, &topology))) {
+
+ m_restorePosition = position() * 10000;
+
+ if (m_state.command == CmdStart)
+ stop();
+
+ if (m_trackInfo[type].outputNodeId != -1) {
+ IMFTopologyNode *node = nullptr;
+ if (SUCCEEDED(topology->GetNodeByID(m_trackInfo[type].outputNodeId, &node))) {
+ topology->RemoveNode(node);
+ node->Release();
+ m_trackInfo[type].outputNodeId = -1;
+ }
+ }
+ if (m_trackInfo[type].sourceNodeId != -1) {
+ IMFTopologyNode *node = nullptr;
+ if (SUCCEEDED(topology->GetNodeByID(m_trackInfo[type].sourceNodeId, &node))) {
+ topology->RemoveNode(node);
+ node->Release();
+ m_trackInfo[type].sourceNodeId = -1;
+ }
+ }
+
+ IMFMediaSource *mediaSource = m_sourceResolver->mediaSource();
+
+ IMFPresentationDescriptor *sourcePD = nullptr;
+ if (SUCCEEDED(mediaSource->CreatePresentationDescriptor(&sourcePD))) {
+
+ if (m_trackInfo[type].currentIndex >= 0 && m_trackInfo[type].currentIndex < nativeIndexes.count())
+ sourcePD->DeselectStream(nativeIndexes.at(m_trackInfo[type].currentIndex));
+
+ m_trackInfo[type].currentIndex = index;
+
+ if (index == -1) {
+ m_session->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
+ } else {
+ int nativeIndex = nativeIndexes.at(index);
+ sourcePD->SelectStream(nativeIndex);
+
+ IMFStreamDescriptor *streamDesc = nullptr;
+ BOOL selected = FALSE;
+
+ if (SUCCEEDED(sourcePD->GetStreamDescriptorByIndex(nativeIndex, &selected, &streamDesc))) {
+ IMFTopologyNode *sourceNode = addSourceNode(topology, mediaSource, sourcePD, streamDesc);
+ if (sourceNode) {
+ IMFTopologyNode *outputNode = addOutputNode(MFPlayerSession::Audio, topology, 0);
+ if (outputNode) {
+ if (SUCCEEDED(sourceNode->ConnectOutput(0, outputNode, 0))) {
+ sourceNode->GetTopoNodeID(&m_trackInfo[type].sourceNodeId);
+ outputNode->GetTopoNodeID(&m_trackInfo[type].outputNodeId);
+ m_session->SetTopology(MFSESSION_SETTOPOLOGY_IMMEDIATE, topology);
+ }
+ outputNode->Release();
+ }
+ sourceNode->Release();
+ }
+ streamDesc->Release();
+ }
+ }
+ m_updatingTopology = true;
+ sourcePD->Release();
+ }
+ topology->Release();
+ }
+}
+
+int MFPlayerSession::activeTrack(QPlatformMediaPlayer::TrackType type)
+{
+ if (type < 0 || type >= QPlatformMediaPlayer::NTrackTypes)
+ return -1;
+ return m_trackInfo[type].currentIndex;
+}
+
+int MFPlayerSession::trackCount(QPlatformMediaPlayer::TrackType type)
+{
+ if (type < 0 || type >= QPlatformMediaPlayer::NTrackTypes)
+ return -1;
+ return m_trackInfo[type].metaData.count();
+}
+
+QMediaMetaData MFPlayerSession::trackMetaData(QPlatformMediaPlayer::TrackType type, int trackNumber)
+{
+ if (type < 0 || type >= QPlatformMediaPlayer::NTrackTypes)
+ return {};
+
+ if (trackNumber < 0 || trackNumber >= m_trackInfo[type].metaData.count())
+ return {};
+
+ return m_trackInfo[type].metaData.at(trackNumber);
+}
+
diff --git a/src/multimedia/platform/windows/player/mfplayersession_p.h b/src/multimedia/platform/windows/player/mfplayersession_p.h
index 18a4b02fa..621fe4f26 100644
--- a/src/multimedia/platform/windows/player/mfplayersession_p.h
+++ b/src/multimedia/platform/windows/player/mfplayersession_p.h
@@ -126,7 +126,13 @@ public:
void setVideoSink(QVideoSink *sink);
+ void setActiveTrack(QPlatformMediaPlayer::TrackType type, int index);
+ int activeTrack(QPlatformMediaPlayer::TrackType type);
+ int trackCount(QPlatformMediaPlayer::TrackType);
+ QMediaMetaData trackMetaData(QPlatformMediaPlayer::TrackType type, int trackNumber);
+
void statusChanged() { if (m_playerControl) m_playerControl->handleStatusChanged(); }
+ void tracksChanged() { if (m_playerControl) m_playerControl->handleTracksChanged(); }
void audioAvailable() { if (m_playerControl) m_playerControl->handleAudioAvailable(); }
void videoAvailable() { if (m_playerControl) m_playerControl->handleVideoAvailable(); }
void durationUpdate(qint64 duration) { if (m_playerControl) m_playerControl->handleDurationUpdate(duration); }
@@ -160,7 +166,9 @@ private:
IMFAudioStreamVolume *m_volumeControl;
IPropertyStore *m_netsourceStatistics;
qint64 m_position = 0;
+ qint64 m_restorePosition = -1;
UINT64 m_duration = 0;
+ bool m_updatingTopology = false;
enum Command
{
@@ -219,6 +227,16 @@ private:
float m_pendingRate;
void updatePendingCommands(Command command);
+ struct TrackInfo
+ {
+ QList<QMediaMetaData> metaData;
+ QList<int> nativeIndexes;
+ int currentIndex = -1;
+ TOPOID sourceNodeId = -1;
+ TOPOID outputNodeId = -1;
+ };
+ TrackInfo m_trackInfo[QPlatformMediaPlayer::NTrackTypes];
+
QMediaPlayer::MediaStatus m_status;
bool m_canScrub;
float m_volume = 1.;
@@ -231,7 +249,7 @@ private:
void createSession();
void setupPlaybackTopology(IMFMediaSource *source, IMFPresentationDescriptor *sourcePD);
- MediaType getStreamType(IMFStreamDescriptor *stream) const;
+ bool getStreamInfo(IMFStreamDescriptor *stream, MFPlayerSession::MediaType *type, QString *name, QString *language) const;
IMFTopologyNode* addSourceNode(IMFTopology* topology, IMFMediaSource* source,
IMFPresentationDescriptor* presentationDesc, IMFStreamDescriptor *streamDesc);
IMFTopologyNode* addOutputNode(MediaType mediaType, IMFTopology* topology, DWORD sinkID);