diff options
Diffstat (limited to 'src/multimedia/platform/windows/player/mfplayersession.cpp')
-rw-r--r-- | src/multimedia/platform/windows/player/mfplayersession.cpp | 97 |
1 files changed, 74 insertions, 23 deletions
diff --git a/src/multimedia/platform/windows/player/mfplayersession.cpp b/src/multimedia/platform/windows/player/mfplayersession.cpp index 3c4fe9929..ebdbff696 100644 --- a/src/multimedia/platform/windows/player/mfplayersession.cpp +++ b/src/multimedia/platform/windows/player/mfplayersession.cpp @@ -59,6 +59,7 @@ #include "mfplayersession_p.h" #include <mferror.h> #include <nserror.h> +#include <winerror.h> #include "private/sourceresolver_p.h" #include "samplegrabber_p.h" #include "mftvideo_p.h" @@ -110,7 +111,7 @@ MFPlayerSession::MFPlayerSession(MFPlayerControl *playerControl) m_request.rate = 1.0f; m_audioSampleGrabber = new AudioSampleGrabberCallback; - m_videoRendererControl = new MFVideoRendererControl; + m_videoRendererControl = new MFVideoRendererControl(this); } void MFPlayerSession::timeout() @@ -152,7 +153,7 @@ void MFPlayerSession::close() m_closing = true; hr = m_session->Close(); if (SUCCEEDED(hr)) { - DWORD dwWaitResult = WaitForSingleObject(m_hCloseEvent, 100); + DWORD dwWaitResult = WaitForSingleObject(m_hCloseEvent, 2000); if (dwWaitResult == WAIT_TIMEOUT) { qWarning() << "session close time out!"; } @@ -187,6 +188,7 @@ void MFPlayerSession::close() CloseHandle(m_hCloseEvent); m_hCloseEvent = 0; m_lastPosition = -1; + m_position = 0; } MFPlayerSession::~MFPlayerSession() @@ -216,7 +218,8 @@ void MFPlayerSession::load(const QUrl &url, QIODevice *stream) createSession(); changeStatus(QMediaPlayer::LoadingMedia); m_sourceResolver->load(url, stream); - m_updateRoutingOnStart = true; + if (url.isLocalFile()) + m_updateRoutingOnStart = true; } positionChanged(position()); } @@ -240,7 +243,17 @@ void MFPlayerSession::handleSourceError(long hr) errorCode = QMediaPlayer::FormatError; errorString = tr("Unsupported media type."); break; + case MF_E_UNSUPPORTED_SCHEME: + errorCode = QMediaPlayer::ResourceError; + errorString = tr("Unsupported URL scheme."); + break; + case QMM_WININET_E_CANNOT_CONNECT: + errorCode = QMediaPlayer::NetworkError; + errorString = tr("A connection with the server could not be established."); + break; default: + qWarning() << "handleSourceError:" + << Qt::showbase << Qt::hex << Qt::uppercasedigits << static_cast<quint32>(hr); errorString = tr("Failed to load source."); break; } @@ -283,9 +296,10 @@ void MFPlayerSession::handleMediaSourceReady() bool MFPlayerSession::getStreamInfo(IMFStreamDescriptor *stream, MFPlayerSession::MediaType *type, QString *name, - QString *language) const + QString *language, + GUID *format) const { - if (!stream || !type || !name || !language) + if (!stream || !type || !name || !language || !format) return false; *type = Unknown; @@ -319,6 +333,13 @@ bool MFPlayerSession::getStreamInfo(IMFStreamDescriptor *stream, else if (guidMajorType == MFMediaType_Video) *type = Video; } + + IMFMediaType *mediaType = nullptr; + if (SUCCEEDED(typeHandler->GetCurrentMediaType(&mediaType))) { + mediaType->GetGUID(MF_MT_SUBTYPE, format); + mediaType->Release(); + } + typeHandler->Release(); } @@ -359,8 +380,9 @@ void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentat MediaType mediaType = Unknown; QString streamName; QString streamLanguage; + GUID format = GUID_NULL; - if (getStreamInfo(streamDesc, &mediaType, &streamName, &streamLanguage)) { + if (getStreamInfo(streamDesc, &mediaType, &streamName, &streamLanguage, &format)) { QPlatformMediaPlayer::TrackType trackType = (mediaType == Audio) ? QPlatformMediaPlayer::AudioStream : QPlatformMediaPlayer::VideoStream; @@ -374,6 +396,7 @@ void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentat m_trackInfo[trackType].metaData.append(metaData); m_trackInfo[trackType].nativeIndexes.append(i); + m_trackInfo[trackType].format = format; if (((m_mediaTypes & mediaType) == 0) && selected) { // Check if this type isn't already added IMFTopologyNode *sourceNode = addSourceNode(topology, source, sourcePD, streamDesc); @@ -481,20 +504,15 @@ IMFTopologyNode* MFPlayerSession::addOutputNode(MediaType mediaType, IMFTopology } auto id = m_audioOutput->device.id(); - if (!id.isEmpty()) { - QString s = QString::fromUtf8(id); - hr = activate->SetString(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, (LPCWSTR)s.utf16()); - } else { - //This is the default one that has been inserted in updateEndpoints(), - //so give the activate a hint that we want to use the device for multimedia playback - //then the media foundation will choose an appropriate one. - - //from MSDN: - //The ERole enumeration defines constants that indicate the role that the system has assigned to an audio endpoint device. - //eMultimedia: Music, movies, narration, and live music recording. - hr = activate->SetUINT32(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, eMultimedia); + if (id.isEmpty()) { + qWarning() << "No audio output"; + activate->Release(); + node->Release(); + return NULL; } + QString s = QString::fromUtf8(id); + hr = activate->SetString(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, (LPCWSTR)s.utf16()); if (FAILED(hr)) { qWarning() << "Failed to set attribute for audio device" << m_audioOutput->device.description(); activate->Release(); @@ -504,6 +522,12 @@ IMFTopologyNode* MFPlayerSession::addOutputNode(MediaType mediaType, IMFTopology } } else if (mediaType == Video) { activate = m_videoRendererControl->createActivate(); + + QSize resolution = m_metaData.value(QMediaMetaData::Resolution).toSize(); + + if (resolution.isValid()) + m_videoRendererControl->setCropRect(QRect(QPoint(), resolution)); + } else { // Unknown stream type. emit error(QMediaPlayer::FormatError, tr("Unknown stream type."), false); @@ -1569,8 +1593,13 @@ ULONG MFPlayerSession::AddRef(void) ULONG MFPlayerSession::Release(void) { LONG cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) + if (cRef == 0) { this->deleteLater(); + + // In rare cases the session has queued events to be run between deleteLater and deleting, + // so we set the parent control to nullptr in order to prevent crashes in the cases. + m_playerControl = nullptr; + } return cRef; } @@ -1654,8 +1683,25 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent) break; } changeStatus(QMediaPlayer::InvalidMedia); - qWarning() << "handleSessionEvent: serious error = " << hrStatus; - emit error(QMediaPlayer::ResourceError, tr("Media session serious error."), true); + qWarning() << "handleSessionEvent: serious error = " + << Qt::showbase << Qt::hex << Qt::uppercasedigits << static_cast<quint32>(hrStatus); + switch (hrStatus) { + case MF_E_NET_READ: + emit error(QMediaPlayer::NetworkError, tr("Error reading from the network."), true); + break; + case MF_E_NET_WRITE: + emit error(QMediaPlayer::NetworkError, tr("Error writing to the network."), true); + break; + case NS_E_FIREWALL: + emit error(QMediaPlayer::NetworkError, tr("Network packets might be blocked by a firewall."), true); + break; + case MF_E_MEDIAPROC_WRONGSTATE: + emit error(QMediaPlayer::ResourceError, tr("Media session state error."), true); + break; + default: + emit error(QMediaPlayer::ResourceError, tr("Media session serious error."), true); + break; + } break; case MESessionRateChanged: // If the rate change succeeded, we've already got the rate @@ -1793,8 +1839,7 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent) if (SUCCEEDED(MFGetService(m_session, MF_RATE_CONTROL_SERVICE, IID_PPV_ARGS(&m_rateControl)))) { if (SUCCEEDED(MFGetService(m_session, MF_RATE_CONTROL_SERVICE, IID_PPV_ARGS(&m_rateSupport)))) { - if ((m_mediaTypes & Video) == Video - && SUCCEEDED(m_rateSupport->IsRateSupported(TRUE, 0, NULL))) + if (SUCCEEDED(m_rateSupport->IsRateSupported(TRUE, 0, NULL))) m_canScrub = true; } BOOL isThin = FALSE; @@ -1903,6 +1948,7 @@ void MFPlayerSession::clear() m_trackInfo[i].currentIndex = -1; m_trackInfo[i].sourceNodeId = TOPOID(-1); m_trackInfo[i].outputNodeId = TOPOID(-1); + m_trackInfo[i].format = GUID_NULL; } if (!m_metaData.isEmpty()) { @@ -1981,6 +2027,11 @@ void MFPlayerSession::setActiveTrack(QPlatformMediaPlayer::TrackType type, int i if (index < -1 || index >= nativeIndexes.count()) return; + // Updating the topology fails if there is a HEVC video stream, + // which causes other issues. Ignoring the change, for now. + if (m_trackInfo[QPlatformMediaPlayer::VideoStream].format == MFVideoFormat_HEVC) + return; + IMFTopology *topology = nullptr; if (SUCCEEDED(m_session->GetFullTopology(QMM_MFSESSION_GETFULLTOPOLOGY_CURRENT, 0, &topology))) { |