From a52aa624e69fa618aa0d29c2a147a7d472751de1 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Wed, 17 Aug 2016 12:59:37 -0700 Subject: Fix instance method not found warning NSView/UIView were only forward declared here which led to warnings when calling methods on instances of them. Change-Id: Ic2b391bb0ed8d45306dc16e2a807ce7fcae5015e Reviewed-by: Gabriel de Dietrich --- src/plugins/avfoundation/mediaplayer/avfvideowidget.mm | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm index f00146d1b..22cd41e69 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm @@ -39,6 +39,12 @@ #include #include +#if defined(Q_OS_MACOS) +#import +#else +#import +#endif + QT_USE_NAMESPACE AVFVideoWidget::AVFVideoWidget(QWidget *parent) -- cgit v1.2.3 From 69296d229eb2f5b5842f7855ef4110e0e4817da2 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 17 Aug 2016 14:03:49 +0200 Subject: AVFoundation: fix memory leak Using 'self' in a block maintains a strong reference to it, the previous code would never release that reference and therefore leak the AVFMediaPlayerSessionObserver object when the session was deleted. Captured variables used in the relevant block are now marked with '__block' to make sure no strong references are maintained. We now also make sure the session still exist when that callback block is called. Change-Id: I847b524d8692559fe5884517abb5b9cc7696b4fd Reviewed-by: Timur Pocheptsov --- .../avfoundation/mediaplayer/avfmediaplayersession.mm | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm index d3ec2ff9c..24b6fe464 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm @@ -35,6 +35,8 @@ #include "avfmediaplayerservice.h" #include "avfvideooutput.h" +#include + #import QT_USE_NAMESPACE @@ -105,15 +107,23 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe //Create an asset for inspection of a resource referenced by a given URL. //Load the values for the asset keys "tracks", "playable". - AVURLAsset *asset = [AVURLAsset URLAssetWithURL:m_URL options:nil]; - NSArray *requestedKeys = [NSArray arrayWithObjects:AVF_TRACKS_KEY, AVF_PLAYABLE_KEY, nil]; + // use __block to avoid maintaining strong references on variables captured by the + // following block callback + __block AVURLAsset *asset = [[AVURLAsset URLAssetWithURL:m_URL options:nil] retain]; + __block NSArray *requestedKeys = [[NSArray arrayWithObjects:AVF_TRACKS_KEY, AVF_PLAYABLE_KEY, nil] retain]; + + __block AVFMediaPlayerSessionObserver *blockSelf = self; + QPointer session(m_session); // Tells the asset to load the values of any of the specified keys that are not already loaded. [asset loadValuesAsynchronouslyForKeys:requestedKeys completionHandler: ^{ dispatch_async( dispatch_get_main_queue(), ^{ - [self prepareToPlayAsset:asset withKeys:requestedKeys]; + if (session) + [blockSelf prepareToPlayAsset:asset withKeys:requestedKeys]; + [asset release]; + [requestedKeys release]; }); }]; } -- cgit v1.2.3 From 0ce67605de8e71f0607b36e2ef28801c3fc5c655 Mon Sep 17 00:00:00 2001 From: Michael Dippold Date: Thu, 18 Aug 2016 09:10:21 -0700 Subject: OpenSL ES: Fix buffer corruption When start is called, the buffer is always filled starting from index 0 without regard to m_nexBuffer. m_nextBuffer could be set to 1 from the previous playback which causes the second buffer to be filled first, which is now the currently playing buffer. This is causing an audible hiccup right after starting in cases where m_nextBuffer starts at 1. Change-Id: Ia0d73638350d5258a51943d7a1c7cd6f22d068ee Reviewed-by: Christian Stromme --- src/plugins/opensles/qopenslesaudiooutput.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/plugins') diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index 3e0ab68c7..94476f58a 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -115,6 +115,7 @@ void QOpenSLESAudioOutput::start(QIODevice *device) m_pullMode = true; m_audioSource = device; + m_nextBuffer = 0; setState(QAudio::ActiveState); setError(QAudio::NoError); -- cgit v1.2.3 From 4025a05c64100b13615f856ac0b403b3623a5cf4 Mon Sep 17 00:00:00 2001 From: Christian Stromme Date: Fri, 12 Aug 2016 14:24:49 +0200 Subject: DirectShow: Restore negotiation of sample type in the io filter This functionality was removed in d44a327da4a956f62cc0d51, but is still needed, as we need to negotiate the media type with the input pin; even if we limit the scope to streaming types. Task-number: QTBUG-55264 Change-Id: I7cc02c5ea17cca9912c29c40813314b04b91bd18 Reviewed-by: Yoann Lopes --- .../directshow/player/directshowiosource.cpp | 82 +++++++++++++++++++--- src/plugins/directshow/player/directshowiosource.h | 2 +- .../directshow/player/directshowmediatypelist.h | 4 +- 3 files changed, 77 insertions(+), 11 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/directshow/player/directshowiosource.cpp b/src/plugins/directshow/player/directshowiosource.cpp index 6fa3c7b9a..1b74415e4 100644 --- a/src/plugins/directshow/player/directshowiosource.cpp +++ b/src/plugins/directshow/player/directshowiosource.cpp @@ -40,6 +40,22 @@ #include #include +static const GUID directshow_subtypes[] = +{ + MEDIASUBTYPE_NULL, + MEDIASUBTYPE_Avi, + MEDIASUBTYPE_Asf, + MEDIASUBTYPE_MPEG1Video, + MEDIASUBTYPE_QTMovie, + MEDIASUBTYPE_WAVE, + MEDIASUBTYPE_AIFF, + MEDIASUBTYPE_AU, + MEDIASUBTYPE_DssVideo, + MEDIASUBTYPE_MPEG1Audio, + MEDIASUBTYPE_MPEG1System, + MEDIASUBTYPE_MPEG1VideoCD +}; + DirectShowIOSource::DirectShowIOSource(DirectShowEventLoop *loop) : m_ref(1) , m_state(State_Stopped) @@ -58,13 +74,29 @@ DirectShowIOSource::DirectShowIOSource(DirectShowEventLoop *loop) // // The filter works in pull mode, the downstream filter is responsible for requesting // samples from this one. + // + QVector mediaTypes; + AM_MEDIA_TYPE type = + { + MEDIATYPE_Stream, // majortype + MEDIASUBTYPE_NULL, // subtype + TRUE, // bFixedSizeSamples + FALSE, // bTemporalCompression + 1, // lSampleSize + GUID_NULL, // formattype + 0, // pUnk + 0, // cbFormat + 0, // pbFormat + }; + + static const int count = sizeof(directshow_subtypes) / sizeof(GUID); + + for (int i = 0; i < count; ++i) { + type.subtype = directshow_subtypes[i]; + mediaTypes.append(type); + } - m_outputType.majortype = MEDIATYPE_Stream; - m_outputType.subtype = MEDIASUBTYPE_NULL; // Wildcard - m_outputType.bFixedSizeSamples = TRUE; - m_outputType.lSampleSize = 1; - - setMediaTypes(QVector() << m_outputType); + setMediaTypes(mediaTypes); } DirectShowIOSource::~DirectShowIOSource() @@ -321,14 +353,44 @@ HRESULT DirectShowIOSource::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) return VFW_E_ALREADY_CONNECTED; // If we get a type from the graph manager, check that we support that - if (pmt && (pmt->majortype != MEDIATYPE_Stream || pmt->subtype != MEDIASUBTYPE_NULL)) + if (pmt && pmt->majortype != MEDIATYPE_Stream) return VFW_E_TYPE_NOT_ACCEPTED; // This filter only works in pull mode, the downstream filter must query for the // AsyncReader interface during ReceiveConnection(). // If it doesn't, we can't connect to it. m_queriedForAsyncReader = false; - HRESULT hr = pReceivePin->ReceiveConnection(this, pmt ? pmt : &m_outputType); + HRESULT hr = 0; + // Negotiation of media type + // - Complete'ish type (Stream with subtype specified). + if (pmt && pmt->subtype != MEDIASUBTYPE_NULL /* aka. GUID_NULL */) { + hr = pReceivePin->ReceiveConnection(this, pmt); + // Update the media type for the current connection. + if (SUCCEEDED(hr)) + m_connectionMediaType = *pmt; + } else if (pmt && pmt->subtype == MEDIATYPE_NULL) { // - Partial type (Stream, but no subtype specified). + m_connectionMediaType = *pmt; + // Check if the receiving pin accepts any of the streaming subtypes. + QVector::const_iterator cit = m_mediaTypes.constBegin(); + while (cit != m_mediaTypes.constEnd()) { + m_connectionMediaType.subtype = cit->subtype; + hr = pReceivePin->ReceiveConnection(this, &m_connectionMediaType); + if (SUCCEEDED(hr)) + break; + ++cit; + } + } else { // - No media type specified. + // Check if the receiving pin accepts any of the streaming types. + QVector::const_iterator cit = m_mediaTypes.constBegin(); + while (cit != m_mediaTypes.constEnd()) { + hr = pReceivePin->ReceiveConnection(this, cit); + if (SUCCEEDED(hr)) { + m_connectionMediaType = *cit; + break; + } + ++cit; + } + } if (SUCCEEDED(hr) && m_queriedForAsyncReader) { m_peerPin = pReceivePin; @@ -341,6 +403,8 @@ HRESULT DirectShowIOSource::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) } if (!m_queriedForAsyncReader) hr = VFW_E_NO_TRANSPORT; + + m_connectionMediaType.clear(); } return hr; @@ -413,7 +477,7 @@ HRESULT DirectShowIOSource::ConnectionMediaType(AM_MEDIA_TYPE *pmt) return VFW_E_NOT_CONNECTED; } else { - DirectShowMediaType::copy(pmt, m_outputType); + DirectShowMediaType::copy(pmt, m_connectionMediaType); return S_OK; } diff --git a/src/plugins/directshow/player/directshowiosource.h b/src/plugins/directshow/player/directshowiosource.h index f5e8ec6d1..60300ba18 100644 --- a/src/plugins/directshow/player/directshowiosource.h +++ b/src/plugins/directshow/player/directshowiosource.h @@ -119,7 +119,7 @@ private: IReferenceClock *m_clock; IMemAllocator *m_allocator; IPin *m_peerPin; - DirectShowMediaType m_outputType; + DirectShowMediaType m_connectionMediaType; QString m_filterName; const QString m_pinId; bool m_queriedForAsyncReader; diff --git a/src/plugins/directshow/player/directshowmediatypelist.h b/src/plugins/directshow/player/directshowmediatypelist.h index 860334532..8dc6e17e4 100644 --- a/src/plugins/directshow/player/directshowmediatypelist.h +++ b/src/plugins/directshow/player/directshowmediatypelist.h @@ -54,9 +54,11 @@ public: virtual HRESULT skipMediaType(int token, int *index, ULONG count); virtual HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration); +protected: + QVector m_mediaTypes; + private: int m_mediaTypeToken; - QVector m_mediaTypes; }; #endif -- cgit v1.2.3 From 7c7a97809b686869d19603bf828a468f3d6e274e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Mon, 22 Aug 2016 20:05:23 +0200 Subject: OpenSL ES: Reset states before starting Some of the state variables were not reset correctly. Change-Id: I22113072320dd1812529c598cda1a5f6cc8c780b Reviewed-by: Michael Dippold Reviewed-by: Yoann Lopes --- src/plugins/opensles/qopenslesaudiooutput.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index 94476f58a..cbc6fca5c 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -116,6 +116,8 @@ void QOpenSLESAudioOutput::start(QIODevice *device) m_pullMode = true; m_audioSource = device; m_nextBuffer = 0; + m_processedBytes = 0; + m_availableBuffers = BUFFER_COUNT; setState(QAudio::ActiveState); setError(QAudio::NoError); @@ -144,6 +146,8 @@ QIODevice *QOpenSLESAudioOutput::start() return Q_NULLPTR; m_pullMode = false; + m_processedBytes = 0; + m_availableBuffers = BUFFER_COUNT; m_audioSource = new SLIODevicePrivate(this); m_audioSource->open(QIODevice::WriteOnly | QIODevice::Unbuffered); -- cgit v1.2.3 From 91d28b48cd7c3ffda21b6d961df29b6aab1caed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Mon, 22 Aug 2016 20:12:23 +0200 Subject: OpenSL ES: Stop the device if it's not stopped already Change-Id: I4a9906d2d5aa1eaf8e67773f79ca217150a53ce5 Reviewed-by: Michael Dippold Reviewed-by: Yoann Lopes --- src/plugins/opensles/qopenslesaudiooutput.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index cbc6fca5c..83691f127 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -110,6 +110,10 @@ QAudio::State QOpenSLESAudioOutput::state() const void QOpenSLESAudioOutput::start(QIODevice *device) { Q_ASSERT(device); + + if (m_state != QAudio::StoppedState) + stop(); + if (!preparePlayer()) return; @@ -142,6 +146,9 @@ void QOpenSLESAudioOutput::start(QIODevice *device) QIODevice *QOpenSLESAudioOutput::start() { + if (m_state != QAudio::StoppedState) + stop(); + if (!preparePlayer()) return Q_NULLPTR; -- cgit v1.2.3 From aa16b8187206c5763429105ec8e5014fb837b925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Mon, 22 Aug 2016 20:10:22 +0200 Subject: OpenSL ES: Release audio device source in push mode The IO device was leaking in push mode, as a new one was created each time start was called. Change-Id: I78bb45e9e4e801772e88104b11d7baedc9e91ba8 Reviewed-by: Michael Dippold Reviewed-by: Yoann Lopes --- src/plugins/opensles/qopenslesaudiooutput.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index 83691f127..06a990ec3 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -614,6 +614,12 @@ void QOpenSLESAudioOutput::stopPlayer() { setState(QAudio::StoppedState); + if (m_audioSource && !m_pullMode) { + m_audioSource->close(); + delete m_audioSource; + m_audioSource = Q_NULLPTR; + } + // We need to change the state manually... if (m_playItf) (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_STOPPED); -- cgit v1.2.3 From 6d95682d7ff282180655f2f384d8aba69c4f67af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Tue, 23 Aug 2016 15:55:28 +0200 Subject: OpenSL ES: Fix EOS handling This fixes the remaining auto tests that were failing. Change-Id: I3b31263e7912422407cb98b4bf2db7080bcfc1a8 Reviewed-by: Yoann Lopes --- src/plugins/opensles/qopenslesaudiooutput.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index 06a990ec3..a76f15b71 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -139,6 +139,9 @@ void QOpenSLESAudioOutput::start(QIODevice *device) m_processedBytes += readSize; } + if (m_processedBytes < 1) + onEOSEvent(); + // Change the state to playing. // We need to do this after filling the buffers or processedBytes might get corrupted. startPlayer(); @@ -380,7 +383,10 @@ void QOpenSLESAudioOutput::bufferAvailable(quint32 count, quint32 playIndex) if (!m_pullMode) { // We're in push mode. // Signal that there is a new open slot in the buffer and return - m_availableBuffers.fetchAndAddRelease(1); + const int val = m_availableBuffers.fetchAndAddRelease(1) + 1; + if (val == BUFFER_COUNT) + QMetaObject::invokeMethod(this, "onEOSEvent", Qt::QueuedConnection); + return; } @@ -388,8 +394,11 @@ void QOpenSLESAudioOutput::bufferAvailable(quint32 count, quint32 playIndex) const int index = m_nextBuffer * m_bufferSize; const qint64 readSize = m_audioSource->read(m_buffers + index, m_bufferSize); - if (1 > readSize) + if (readSize < 1) { + QMetaObject::invokeMethod(this, "onEOSEvent", Qt::QueuedConnection); return; + } + if (SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf, m_buffers + index, -- cgit v1.2.3