diff options
author | Liang Qi <liang.qi@qt.io> | 2016-09-21 09:28:06 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-09-21 09:28:06 +0200 |
commit | e1ae1235f259393e72e4a2e0d77278e9054405fb (patch) | |
tree | 04f57d7b2a9429844306c55e9604f10562ba9783 /src/plugins | |
parent | 2e556aef9375377439b9b6da8d455fe891abfd7c (diff) | |
parent | 01c9322bfe918b886468eb520d77b21b6d8c0c11 (diff) |
Merge remote-tracking branch 'origin/5.8' into dev
Conflicts:
src/imports/multimedia/multimedia.cpp
Change-Id: I38899391ec8d2fcec6f2d46514286759f7a27629
Diffstat (limited to 'src/plugins')
21 files changed, 604 insertions, 210 deletions
diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm index 87bb08e5c..473a18884 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm @@ -41,6 +41,8 @@ #include "avfmediaplayerservice.h" #include "avfvideooutput.h" +#include <qpointer.h> + #import <AVFoundation/AVFoundation.h> QT_USE_NAMESPACE @@ -111,15 +113,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<AVFMediaPlayerSession> 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]; }); }]; } diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm index 3b270f9b6..7eb5a71cf 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm @@ -45,6 +45,12 @@ #include <QtGui/QPaintEvent> #include <QtGui/QPainter> +#if defined(Q_OS_MACOS) +#import <AppKit/AppKit.h> +#else +#import <UIKit/UIKit.h> +#endif + QT_USE_NAMESPACE AVFVideoWidget::AVFVideoWidget(QWidget *parent) diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index 509057ba1..5587b479c 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -174,6 +174,8 @@ QVideoFrame::PixelFormat pixelFormatFromMediaSubtype(GUID uid) return QVideoFrame::Format_YUYV; else if (uid == MEDIASUBTYPE_NV12) return QVideoFrame::Format_NV12; + else if (uid == MEDIASUBTYPE_MJPG) + return QVideoFrame::Format_Jpeg; else if (uid == MEDIASUBTYPE_IMC1) return QVideoFrame::Format_IMC1; else if (uid == MEDIASUBTYPE_IMC2) diff --git a/src/plugins/directshow/player/directshowiosource.cpp b/src/plugins/directshow/player/directshowiosource.cpp index 4dc8bec3d..3c44dd1ed 100644 --- a/src/plugins/directshow/player/directshowiosource.cpp +++ b/src/plugins/directshow/player/directshowiosource.cpp @@ -47,6 +47,22 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qurl.h> +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) @@ -65,13 +81,26 @@ DirectShowIOSource::DirectShowIOSource(DirectShowEventLoop *loop) // // The filter works in pull mode, the downstream filter is responsible for requesting // samples from this one. - - m_outputType.majortype = MEDIATYPE_Stream; - m_outputType.subtype = MEDIASUBTYPE_NULL; // Wildcard - m_outputType.bFixedSizeSamples = TRUE; - m_outputType.lSampleSize = 1; - - m_supportedMediaTypes.append(m_outputType); + // + 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]; + m_supportedMediaTypes.append(type); + } } DirectShowIOSource::~DirectShowIOSource() @@ -328,14 +357,40 @@ 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. + for (const DirectShowMediaType &t : qAsConst(m_supportedMediaTypes)) { + m_connectionMediaType.subtype = t.subtype; + hr = pReceivePin->ReceiveConnection(this, &m_connectionMediaType); + if (SUCCEEDED(hr)) + break; + } + } else { // - No media type specified. + // Check if the receiving pin accepts any of the streaming types. + for (const DirectShowMediaType &t : qAsConst(m_supportedMediaTypes)) { + hr = pReceivePin->ReceiveConnection(this, &t); + if (SUCCEEDED(hr)) { + m_connectionMediaType = t; + break; + } + } + } if (SUCCEEDED(hr) && m_queriedForAsyncReader) { m_peerPin = pReceivePin; @@ -348,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; @@ -420,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 efcde7a27..702bfed61 100644 --- a/src/plugins/directshow/player/directshowiosource.h +++ b/src/plugins/directshow/player/directshowiosource.h @@ -123,7 +123,7 @@ private: IReferenceClock *m_clock; IMemAllocator *m_allocator; IPin *m_peerPin; - DirectShowMediaType m_outputType; + DirectShowMediaType m_connectionMediaType; QList<DirectShowMediaType> m_supportedMediaTypes; QString m_filterName; const QString m_pinId; diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index 26f2380b2..70d77a380 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -114,11 +114,18 @@ QAudio::State QOpenSLESAudioOutput::state() const void QOpenSLESAudioOutput::start(QIODevice *device) { Q_ASSERT(device); + + if (m_state != QAudio::StoppedState) + stop(); + if (!preparePlayer()) return; m_pullMode = true; m_audioSource = device; + m_nextBuffer = 0; + m_processedBytes = 0; + m_availableBuffers = BUFFER_COUNT; setState(QAudio::ActiveState); setError(QAudio::NoError); @@ -136,6 +143,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(); @@ -143,10 +153,15 @@ void QOpenSLESAudioOutput::start(QIODevice *device) QIODevice *QOpenSLESAudioOutput::start() { + if (m_state != QAudio::StoppedState) + stop(); + if (!preparePlayer()) 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); @@ -372,7 +387,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; } @@ -380,8 +398,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, @@ -606,6 +627,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); diff --git a/src/plugins/videonode/videonode.pro b/src/plugins/videonode/videonode.pro index b7b18cdcf..5fbcaecd4 100644 --- a/src/plugins/videonode/videonode.pro +++ b/src/plugins/videonode/videonode.pro @@ -1,4 +1,5 @@ TEMPLATE = subdirs +QT_FOR_CONFIG += gui-private config_gpu_vivante { SUBDIRS += imx6 diff --git a/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp b/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp index 0fa618fe4..e1a46841d 100644 --- a/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp +++ b/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp @@ -54,7 +54,7 @@ QWasapiAudioDeviceInfo::QWasapiAudioDeviceInfo(QByteArray dev, QAudio::Mode mode QAudioFormat referenceFormat = m_interface->m_mixFormat; - const int rates[] = {8000, 11025, 160000, 22050, 32000, 44100, 48000, 88200, 96000, 192000}; + const int rates[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 192000}; for (int rate : rates) { QAudioFormat f = referenceFormat; f.setSampleRate(rate); diff --git a/src/plugins/wasapi/qwasapiaudioinput.cpp b/src/plugins/wasapi/qwasapiaudioinput.cpp index 3bcf50367..22a77df38 100644 --- a/src/plugins/wasapi/qwasapiaudioinput.cpp +++ b/src/plugins/wasapi/qwasapiaudioinput.cpp @@ -120,7 +120,7 @@ qint64 WasapiInputDevicePrivate::readData(char* data, qint64 len) qFatal("Could not release buffer"); if (m_input->m_interval && m_input->m_openTime.elapsed() - m_input->m_openTimeOffset > m_input->m_interval) { - QMetaObject::invokeMethod(m_input, "notify", Qt::QueuedConnection); + emit m_input->notify(); m_input->m_openTimeOffset = m_input->m_openTime.elapsed(); } @@ -128,8 +128,7 @@ qint64 WasapiInputDevicePrivate::readData(char* data, qint64 len) if (m_input->m_currentState != QAudio::ActiveState) { m_input->m_currentState = QAudio::ActiveState; - QMetaObject::invokeMethod(m_input, "stateChanged", Qt::QueuedConnection, - Q_ARG(QAudio::State, QAudio::ActiveState)); + emit m_input->stateChanged(m_input->m_currentState); } return readBytes; } @@ -192,13 +191,9 @@ qreal QWasapiAudioInput::volume() const void QWasapiAudioInput::process() { qCDebug(lcMmAudioInput) << __FUNCTION__; - const quint32 channelCount = m_currentFormat.channelCount(); - const quint32 sampleBytes = m_currentFormat.sampleSize() / 8; - BYTE* buffer; - HRESULT hr; DWORD waitRet; - bool processing = true; + m_processing = true; do { waitRet = WaitForSingleObjectEx(m_event, 2000, FALSE); if (waitRet != WAIT_OBJECT_0) { @@ -210,67 +205,75 @@ void QWasapiAudioInput::process() if (m_currentState != QAudio::ActiveState && m_currentState != QAudio::IdleState) break; + QMetaObject::invokeMethod(this, "processBuffer", Qt::QueuedConnection); + } while (m_processing); +} - if (!m_pullMode) { - QMetaObject::invokeMethod(m_eventDevice, "readyRead", Qt::QueuedConnection); - ResetEvent(m_event); - continue; - } +void QWasapiAudioInput::processBuffer() +{ + if (!m_pullMode) { + emit m_eventDevice->readyRead(); + ResetEvent(m_event); + return; + } - quint32 packetFrames; - hr = m_capture->GetNextPacketSize(&packetFrames); + QMutexLocker locker(&m_mutex); + const quint32 channelCount = m_currentFormat.channelCount(); + const quint32 sampleBytes = m_currentFormat.sampleSize() / 8; + BYTE* buffer; + HRESULT hr; - while (packetFrames != 0 && m_currentState == QAudio::ActiveState) { - DWORD flags; - quint64 devicePosition; - hr = m_capture->GetBuffer(&buffer, &packetFrames, &flags, &devicePosition, NULL); - if (hr != S_OK) { - m_currentError = QAudio::FatalError; - QMetaObject::invokeMethod(this, "errorChanged", Qt::QueuedConnection, - Q_ARG(QAudio::Error, QAudio::UnderrunError)); - // Also Error Buffers need to be released - hr = m_capture->ReleaseBuffer(packetFrames); - qCDebug(lcMmAudioInput) << __FUNCTION__ << "Could not acquire input buffer."; - return; - } - const quint32 writeBytes = packetFrames * channelCount * sampleBytes; - if (Q_UNLIKELY(flags & AUDCLNT_BUFFERFLAGS_SILENT)) { - // In case this flag is set, user is supposed to ignore the content - // of the buffer and manually write silence - qCDebug(lcMmAudioInput) << __FUNCTION__ << "AUDCLNT_BUFFERFLAGS_SILENT: " - << "Ignoring buffer and writing silence."; - buffer = new BYTE[writeBytes]; - memset(buffer, 0, writeBytes); - } + quint32 packetFrames; + hr = m_capture->GetNextPacketSize(&packetFrames); + + while (packetFrames != 0 && m_currentState == QAudio::ActiveState) { + DWORD flags; + quint64 devicePosition; + hr = m_capture->GetBuffer(&buffer, &packetFrames, &flags, &devicePosition, NULL); + if (hr != S_OK) { + m_currentError = QAudio::FatalError; + emit errorChanged(m_currentError); + // Also Error Buffers need to be released + hr = m_capture->ReleaseBuffer(packetFrames); + qCDebug(lcMmAudioInput) << __FUNCTION__ << "Could not acquire input buffer."; + return; + } + const quint32 writeBytes = packetFrames * channelCount * sampleBytes; + if (Q_UNLIKELY(flags & AUDCLNT_BUFFERFLAGS_SILENT)) { + // In case this flag is set, user is supposed to ignore the content + // of the buffer and manually write silence + qCDebug(lcMmAudioInput) << __FUNCTION__ << "AUDCLNT_BUFFERFLAGS_SILENT: " + << "Ignoring buffer and writing silence."; + buffer = new BYTE[writeBytes]; + memset(buffer, 0, writeBytes); + } - qint64 written = m_eventDevice->write(reinterpret_cast<const char *>(buffer), writeBytes); + const qint64 written = m_eventDevice->write(reinterpret_cast<const char *>(buffer), writeBytes); - if (Q_UNLIKELY(flags & AUDCLNT_BUFFERFLAGS_SILENT)) - delete [] buffer; + if (Q_UNLIKELY(flags & AUDCLNT_BUFFERFLAGS_SILENT)) + delete [] buffer; - if (written < static_cast<qint64>(writeBytes)) { - if (m_currentError != QAudio::UnderrunError) { - m_currentError = QAudio::UnderrunError; - QMetaObject::invokeMethod(this, "errorChanged", Qt::QueuedConnection, - Q_ARG(QAudio::Error, QAudio::UnderrunError)); - } + if (written < static_cast<qint64>(writeBytes)) { + if (m_currentError != QAudio::UnderrunError) { + m_currentError = QAudio::UnderrunError; + emit errorChanged(m_currentError); } - hr = m_capture->ReleaseBuffer(packetFrames); - if (hr != S_OK) - qFatal("Could not release buffer"); + } + hr = m_capture->ReleaseBuffer(packetFrames); + if (hr != S_OK) + qFatal("Could not release buffer"); - m_bytesProcessed += writeBytes; + m_bytesProcessed += writeBytes; - hr = m_capture->GetNextPacketSize(&packetFrames); - } - ResetEvent(m_event); + hr = m_capture->GetNextPacketSize(&packetFrames); + } + ResetEvent(m_event); - if (m_interval && m_openTime.elapsed() - m_openTimeOffset > m_interval) { - QMetaObject::invokeMethod(this, "notify", Qt::QueuedConnection); - m_openTimeOffset = m_openTime.elapsed(); - } - processing = m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState; - } while (processing); + if (m_interval && m_openTime.elapsed() - m_openTimeOffset > m_interval) { + emit notify(); + m_openTimeOffset = m_openTime.elapsed(); + } + m_processing = m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState; } bool QWasapiAudioInput::initStart(bool pull) diff --git a/src/plugins/wasapi/qwasapiaudioinput.h b/src/plugins/wasapi/qwasapiaudioinput.h index cb2f46436..3fd7315c1 100644 --- a/src/plugins/wasapi/qwasapiaudioinput.h +++ b/src/plugins/wasapi/qwasapiaudioinput.h @@ -88,6 +88,8 @@ public: qreal volume() const Q_DECL_OVERRIDE; void process(); +public slots: + void processBuffer(); private: bool initStart(bool pull); friend class WasapiInputDevicePrivate; @@ -112,6 +114,7 @@ private: quint32 m_bufferBytes; HANDLE m_event; QWasapiProcessThread *m_eventThread; + QAtomicInt m_processing; QIODevice *m_eventDevice; }; diff --git a/src/plugins/wasapi/qwasapiaudiooutput.cpp b/src/plugins/wasapi/qwasapiaudiooutput.cpp index 53f4f2710..1b0f64451 100644 --- a/src/plugins/wasapi/qwasapiaudiooutput.cpp +++ b/src/plugins/wasapi/qwasapiaudiooutput.cpp @@ -206,13 +206,9 @@ qreal QWasapiAudioOutput::volume() const void QWasapiAudioOutput::process() { qCDebug(lcMmAudioOutput) << __FUNCTION__; - const quint32 channelCount = m_currentFormat.channelCount(); - const quint32 sampleBytes = m_currentFormat.sampleSize() / 8; - BYTE* buffer; - HRESULT hr; DWORD waitRet; - bool processing = true; + m_processing = true; do { waitRet = WaitForSingleObjectEx(m_event, 2000, FALSE); if (waitRet != WAIT_OBJECT_0) { @@ -224,51 +220,59 @@ void QWasapiAudioOutput::process() if (m_currentState != QAudio::ActiveState && m_currentState != QAudio::IdleState) break; + QMetaObject::invokeMethod(this, "processBuffer", Qt::QueuedConnection); + } while (m_processing); +} - quint32 paddingFrames; - hr = m_interface->m_client->GetCurrentPadding(&paddingFrames); +void QWasapiAudioOutput::processBuffer() +{ + QMutexLocker locker(&m_mutex); - quint32 availableFrames = m_bufferFrames - paddingFrames; - hr = m_renderer->GetBuffer(availableFrames, &buffer); - if (hr != S_OK) { - m_currentError = QAudio::UnderrunError; - QMetaObject::invokeMethod(this, "errorChanged", Qt::QueuedConnection, - Q_ARG(QAudio::Error, QAudio::UnderrunError)); - // Also Error Buffers need to be released - hr = m_renderer->ReleaseBuffer(availableFrames, 0); - ResetEvent(m_event); - continue; // We will continue trying - } + const quint32 channelCount = m_currentFormat.channelCount(); + const quint32 sampleBytes = m_currentFormat.sampleSize() / 8; + BYTE* buffer; + HRESULT hr; - const quint32 readBytes = availableFrames * channelCount * sampleBytes; - qint64 read = m_eventDevice->read((char*)buffer, readBytes); - if (read < static_cast<qint64>(readBytes)) { - // Fill the rest of the buffer with zero to avoid audio glitches - if (m_currentError != QAudio::UnderrunError) { - m_currentError = QAudio::UnderrunError; - QMetaObject::invokeMethod(this, "errorChanged", Qt::QueuedConnection, - Q_ARG(QAudio::Error, QAudio::UnderrunError)); - } - if (m_currentState != QAudio::IdleState) { - m_currentState = QAudio::IdleState; - QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, - Q_ARG(QAudio::State, QAudio::IdleState)); - } - } + quint32 paddingFrames; + hr = m_interface->m_client->GetCurrentPadding(&paddingFrames); + const quint32 availableFrames = m_bufferFrames - paddingFrames; + hr = m_renderer->GetBuffer(availableFrames, &buffer); + if (hr != S_OK) { + m_currentError = QAudio::UnderrunError; + emit errorChanged(m_currentError); + // Also Error Buffers need to be released hr = m_renderer->ReleaseBuffer(availableFrames, 0); - if (hr != S_OK) - qFatal("Could not release buffer"); ResetEvent(m_event); + return; + } - if (m_interval && m_openTime.elapsed() - m_openTimeOffset > m_interval) { - QMetaObject::invokeMethod(this, "notify", Qt::QueuedConnection); - m_openTimeOffset = m_openTime.elapsed(); + const quint32 readBytes = availableFrames * channelCount * sampleBytes; + const qint64 read = m_eventDevice->read((char*)buffer, readBytes); + if (read < static_cast<qint64>(readBytes)) { + // Fill the rest of the buffer with zero to avoid audio glitches + if (m_currentError != QAudio::UnderrunError) { + m_currentError = QAudio::UnderrunError; + emit errorChanged(m_currentError); } + if (m_currentState != QAudio::IdleState) { + m_currentState = QAudio::IdleState; + emit stateChanged(m_currentState); + } + } + + hr = m_renderer->ReleaseBuffer(availableFrames, 0); + if (hr != S_OK) + qFatal("Could not release buffer"); + ResetEvent(m_event); + + if (m_interval && m_openTime.elapsed() - m_openTimeOffset > m_interval) { + emit notify(); + m_openTimeOffset = m_openTime.elapsed(); + } - m_bytesProcessed += read; - processing = m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState; - } while (processing); + m_bytesProcessed += read; + m_processing = m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState; } bool QWasapiAudioOutput::initStart(bool pull) diff --git a/src/plugins/wasapi/qwasapiaudiooutput.h b/src/plugins/wasapi/qwasapiaudiooutput.h index 247a07160..118731af9 100644 --- a/src/plugins/wasapi/qwasapiaudiooutput.h +++ b/src/plugins/wasapi/qwasapiaudiooutput.h @@ -89,6 +89,8 @@ public: qreal volume() const Q_DECL_OVERRIDE; void process(); +public slots: + void processBuffer(); private: bool initStart(bool pull); friend class WasapiOutputDevicePrivate; @@ -113,6 +115,7 @@ private: quint32 m_bufferBytes; HANDLE m_event; QWasapiProcessThread *m_eventThread; + QAtomicInt m_processing; QIODevice *m_eventDevice; }; diff --git a/src/plugins/wasapi/qwasapiutils.cpp b/src/plugins/wasapi/qwasapiutils.cpp index 6340a3b01..727c94c23 100644 --- a/src/plugins/wasapi/qwasapiutils.cpp +++ b/src/plugins/wasapi/qwasapiutils.cpp @@ -182,6 +182,13 @@ QByteArray QWasapiUtils::defaultDevice(QAudio::Mode mode) { qCDebug(lcMmUtils) << __FUNCTION__ << mode; + QList<QByteArray> &deviceNames = mode == QAudio::AudioInput ? gMapping->inputDeviceNames : gMapping->outputDeviceNames; + QList<QString> &deviceIds = mode == QAudio::AudioInput ? gMapping->inputDeviceIds : gMapping->outputDeviceIds; + if (deviceNames.isEmpty() || deviceIds.isEmpty()) // Initialize + availableDevices(mode); + if (deviceNames.isEmpty() || deviceIds.isEmpty()) // No audio devices at all + return QByteArray(); + ComPtr<IMediaDeviceStatics> mediaDeviceStatics; HRESULT hr; @@ -198,7 +205,9 @@ QByteArray QWasapiUtils::defaultDevice(QAudio::Mode mode) const wchar_t *dadWStr = defaultAudioDevice.GetRawBuffer(&dADSize); const QString defaultAudioDeviceId = QString::fromWCharArray(dadWStr, dADSize); - return defaultAudioDeviceId.toLocal8Bit(); + Q_ASSERT(deviceIds.indexOf(defaultAudioDeviceId) != -1); + + return deviceNames.at(deviceIds.indexOf(defaultAudioDeviceId)); } QList<QByteArray> QWasapiUtils::availableDevices(QAudio::Mode mode) diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp index c32a5f2e2..f81a2e94d 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.cpp +++ b/src/plugins/winrt/qwinrtcameracontrol.cpp @@ -42,6 +42,7 @@ #include "qwinrtvideodeviceselectorcontrol.h" #include "qwinrtcameraimagecapturecontrol.h" #include "qwinrtimageencodercontrol.h" +#include "qwinrtcameraflashcontrol.h" #include "qwinrtcamerafocuscontrol.h" #include "qwinrtcameralockscontrol.h" @@ -554,6 +555,7 @@ public: QPointer<QWinRTVideoDeviceSelectorControl> videoDeviceSelector; QPointer<QWinRTCameraImageCaptureControl> imageCaptureControl; QPointer<QWinRTImageEncoderControl> imageEncoderControl; + QPointer<QWinRTCameraFlashControl> cameraFlashControl; QPointer<QWinRTCameraFocusControl> cameraFocusControl; QPointer<QWinRTCameraLocksControl> cameraLocksControl; QAtomicInt framesMapped; @@ -578,6 +580,7 @@ QWinRTCameraControl::QWinRTCameraControl(QObject *parent) d->videoDeviceSelector = new QWinRTVideoDeviceSelectorControl(this); d->imageCaptureControl = new QWinRTCameraImageCaptureControl(this); d->imageEncoderControl = new QWinRTImageEncoderControl(this); + d->cameraFlashControl = new QWinRTCameraFlashControl(this); d->cameraFocusControl = new QWinRTCameraFocusControl(this); d->cameraLocksControl = new QWinRTCameraLocksControl(this); @@ -815,6 +818,12 @@ QImageEncoderControl *QWinRTCameraControl::imageEncoderControl() const return d->imageEncoderControl; } +QCameraFlashControl *QWinRTCameraControl::cameraFlashControl() const +{ + Q_D(const QWinRTCameraControl); + return d->cameraFlashControl; +} + QCameraFocusControl *QWinRTCameraControl::cameraFocusControl() const { Q_D(const QWinRTCameraControl); @@ -940,6 +949,8 @@ HRESULT QWinRTCameraControl::initialize() hr = advancedVideoDeviceController->get_FocusControl(&d->focusControl); Q_ASSERT_SUCCEEDED(hr); + d->cameraFlashControl->initialize(advancedVideoDeviceController); + boolean isFocusSupported; hr = d->focusControl->get_Supported(&isFocusSupported); Q_ASSERT_SUCCEEDED(hr); diff --git a/src/plugins/winrt/qwinrtcameracontrol.h b/src/plugins/winrt/qwinrtcameracontrol.h index 85dd4d44b..f978a8b2c 100644 --- a/src/plugins/winrt/qwinrtcameracontrol.h +++ b/src/plugins/winrt/qwinrtcameracontrol.h @@ -69,6 +69,7 @@ class QVideoRendererControl; class QVideoDeviceSelectorControl; class QCameraImageCaptureControl; class QImageEncoderControl; +class QCameraFlashControl; class QCameraFocusControl; class QCameraLocksControl; @@ -95,6 +96,7 @@ public: QVideoDeviceSelectorControl *videoDeviceSelector() const; QCameraImageCaptureControl *imageCaptureControl() const; QImageEncoderControl *imageEncoderControl() const; + QCameraFlashControl *cameraFlashControl() const; QCameraFocusControl *cameraFocusControl() const; QCameraLocksControl *cameraLocksControl() const; diff --git a/src/plugins/winrt/qwinrtcameraflashcontrol.cpp b/src/plugins/winrt/qwinrtcameraflashcontrol.cpp new file mode 100644 index 000000000..1ea877672 --- /dev/null +++ b/src/plugins/winrt/qwinrtcameraflashcontrol.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwinrtcameraflashcontrol.h" +#include "qwinrtcameracontrol.h" +#include <QtCore/QTimer> +#include <QtCore/qfunctions_winrt.h> +#include <QtCore/private/qeventdispatcher_winrt_p.h> + +#include <windows.media.devices.h> +#include <wrl.h> +#include <functional> + +using namespace Microsoft::WRL; +using namespace ABI::Windows::Media::Devices; + +QT_BEGIN_NAMESPACE + +class QWinRTCameraFlashControlPrivate +{ +public: + ComPtr<IFlashControl> flashControl; + + QList<QCameraExposure::FlashModes> supportedModes; + QCameraExposure::FlashModes currentModes; + bool initialized; +}; + +QWinRTCameraFlashControl::QWinRTCameraFlashControl(QWinRTCameraControl *parent) + : QCameraFlashControl(parent), d_ptr(new QWinRTCameraFlashControlPrivate) +{ + qCDebug(lcMMCamera) << __FUNCTION__ << parent; + Q_D(QWinRTCameraFlashControl); + + d->initialized = false; + d->currentModes = QCameraExposure::FlashOff; +} + +void QWinRTCameraFlashControl::initialize(Microsoft::WRL::ComPtr<IAdvancedVideoCaptureDeviceController2> &controller) +{ + qCDebug(lcMMCamera) << __FUNCTION__; + Q_D(QWinRTCameraFlashControl); + + d->initialized = false; + + d->supportedModes.clear(); + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([d, controller]() { + HRESULT hr; + hr = controller->get_FlashControl(&d->flashControl); + RETURN_HR_IF_FAILED("Could not access flash control."); + + boolean oldAuto; + boolean oldEnabled; + // IFlashControl::get_Supported() is only valid for additional + // controls (RedEye, etc.) so we have to manually try to set + // and reset flash + if (SUCCEEDED(d->flashControl->get_Auto(&oldAuto))) { + hr = d->flashControl->put_Auto(!oldAuto); + if (SUCCEEDED(hr)) { + d->flashControl->put_Auto(oldAuto); + d->supportedModes.append(QCameraExposure::FlashAuto); + } + } + + if (SUCCEEDED(d->flashControl->get_Enabled(&oldEnabled))) { + hr = d->flashControl->put_Enabled(!oldEnabled); + if (SUCCEEDED(hr)) { + d->flashControl->put_Enabled(oldEnabled); + d->supportedModes.append(QCameraExposure::FlashOff); + d->supportedModes.append(QCameraExposure::FlashOn); + } + } + + boolean val; + hr = d->flashControl->get_Supported(&val); + if (SUCCEEDED(hr) && val) { + hr = d->flashControl->get_RedEyeReductionSupported(&val); + if (SUCCEEDED(hr) && val) + d->supportedModes.append(QCameraExposure::FlashRedEyeReduction); + + // ### There is no Qt API to actually set the power values. + // However query if the camera could theoretically do it + hr = d->flashControl->get_PowerSupported(&val); + if (SUCCEEDED(hr) && val) + d->supportedModes.append(QCameraExposure::FlashManual); + } + + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); + d->initialized = true; + setFlashMode(d->currentModes); +} + +QCameraExposure::FlashModes QWinRTCameraFlashControl::flashMode() const +{ + Q_D(const QWinRTCameraFlashControl); + return d->currentModes; +} + +void QWinRTCameraFlashControl::setFlashMode(QCameraExposure::FlashModes mode) +{ + qCDebug(lcMMCamera) << __FUNCTION__ << mode; + Q_D(QWinRTCameraFlashControl); + + if (!d->initialized) { + d->currentModes = mode; + return; + } + + if (!isFlashModeSupported(mode)) + return; + + QEventDispatcherWinRT::runOnXamlThread([d, mode]() { + HRESULT hr; + if (mode.testFlag(QCameraExposure::FlashAuto)) { + hr = d->flashControl->put_Enabled(true); + RETURN_OK_IF_FAILED("Could not set flash mode on."); + hr = d->flashControl->put_Auto(true); + RETURN_OK_IF_FAILED("Could not set flash mode auto."); + d->currentModes = QCameraExposure::FlashAuto; + } else if (mode.testFlag(QCameraExposure::FlashOn)) { + hr = d->flashControl->put_Enabled(true); + RETURN_OK_IF_FAILED("Could not set flash mode on."); + hr = d->flashControl->put_Auto(false); + RETURN_OK_IF_FAILED("Could not disable flash auto mode."); + d->currentModes = QCameraExposure::FlashOn; + } else if (mode.testFlag(QCameraExposure::FlashRedEyeReduction)) { + hr = d->flashControl->put_Enabled(true); + RETURN_OK_IF_FAILED("Could not set flash mode on."); + hr = d->flashControl->put_RedEyeReduction(true); + RETURN_OK_IF_FAILED("Could not set flash mode red eye reduction."); + d->currentModes = QCameraExposure::FlashRedEyeReduction; + } else { + hr = d->flashControl->put_Enabled(false); + RETURN_OK_IF_FAILED("Could not set flash mode off."); + d->currentModes = QCameraExposure::FlashOff; + } + return S_OK; + }); +} + +bool QWinRTCameraFlashControl::isFlashModeSupported(QCameraExposure::FlashModes mode) const +{ + Q_D(const QWinRTCameraFlashControl); + qCDebug(lcMMCamera) << __FUNCTION__ << mode; + return d->initialized ? d->supportedModes.contains(mode) : false; +} + +bool QWinRTCameraFlashControl::isFlashReady() const +{ + qCDebug(lcMMCamera) << __FUNCTION__; + // No native API to query state + return true; +} + +QT_END_NAMESPACE diff --git a/src/plugins/winrt/qwinrtcameraflashcontrol.h b/src/plugins/winrt/qwinrtcameraflashcontrol.h new file mode 100644 index 000000000..335329037 --- /dev/null +++ b/src/plugins/winrt/qwinrtcameraflashcontrol.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINRTCAMERAFLASHCONTROL_H +#define QWINRTCAMERAFLASHCONTROL_H +#include <qcameraflashcontrol.h> + +#include <wrl.h> + +namespace ABI { + namespace Windows { + namespace Media { + namespace Devices { + struct IAdvancedVideoCaptureDeviceController2; + } + } + } +} + +QT_BEGIN_NAMESPACE + +class QWinRTCameraControl; +class QWinRTCameraFlashControlPrivate; +class QWinRTCameraFlashControl : public QCameraFlashControl +{ + Q_OBJECT +public: + explicit QWinRTCameraFlashControl(QWinRTCameraControl *parent); + + void initialize(Microsoft::WRL::ComPtr<ABI::Windows::Media::Devices::IAdvancedVideoCaptureDeviceController2> &controller); + + QCameraExposure::FlashModes flashMode() const Q_DECL_OVERRIDE; + void setFlashMode(QCameraExposure::FlashModes mode) Q_DECL_OVERRIDE; + bool isFlashModeSupported(QCameraExposure::FlashModes mode) const Q_DECL_OVERRIDE; + + bool isFlashReady() const Q_DECL_OVERRIDE; + +private: + QScopedPointer<QWinRTCameraFlashControlPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTCameraFlashControl) +}; + +#endif // QWINRTCAMERAFLASHCONTROL_H diff --git a/src/plugins/winrt/qwinrtcamerafocuscontrol.cpp b/src/plugins/winrt/qwinrtcamerafocuscontrol.cpp index ef637ac37..aeefc9241 100644 --- a/src/plugins/winrt/qwinrtcamerafocuscontrol.cpp +++ b/src/plugins/winrt/qwinrtcamerafocuscontrol.cpp @@ -79,7 +79,41 @@ QCameraFocus::FocusModes QWinRTCameraFocusControl::focusMode() const void QWinRTCameraFocusControl::setFocusMode(QCameraFocus::FocusModes modes) { - QMetaObject::invokeMethod(this, "applyFocusMode", Qt::QueuedConnection, Q_ARG(QCameraFocus::FocusModes, modes)); + Q_D(QWinRTCameraFocusControl); + if (d->focusModes == modes) + return; + QWinRTCameraControl *cameraControl = static_cast<QWinRTCameraControl *>(parent()); + Q_ASSERT(cameraControl); + if (!modes) { + cameraControl->emitError(QCamera::InvalidRequestError, QStringLiteral("Can't set empty camera focus modes.")); + return; + } + if (!d->focusModeInitialized) { + d->focusModes = modes; + emit focusModeChanged(modes); + return; + } + if (!isFocusModeSupported(modes)) { + cameraControl->emitError(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera focus modes.")); + return; + } + if (modes.testFlag(QCameraFocus::ContinuousFocus)) { + if (QCameraFocus::FocusPointCustom == d->focusPointMode) { + cameraControl->emitError(QCamera::NotSupportedFeatureError, + QStringLiteral("Unsupported camera focus modes: ContinuousFocus with FocusPointCustom.")); + return; + } else if (!d->imageCaptureIdle) { + cameraControl->emitError(QCamera::NotSupportedFeatureError, + QStringLiteral("Can't set ContinuousFocus camera focus mode while capturing image.")); + return; + } + } + if (!cameraControl->setFocus(modes)) + return; + if (modes.testFlag(QCameraFocus::ContinuousFocus) || d->focusModes.testFlag(QCameraFocus::ContinuousFocus)) + cameraControl->focus(); + d->focusModes = modes; + emit focusModeChanged(modes); } bool QWinRTCameraFocusControl::isFocusModeSupported(QCameraFocus::FocusModes modes) const @@ -96,7 +130,32 @@ QCameraFocus::FocusPointMode QWinRTCameraFocusControl::focusPointMode() const void QWinRTCameraFocusControl::setFocusPointMode(QCameraFocus::FocusPointMode mode) { - QMetaObject::invokeMethod(this, "applyFocusPointMode", Qt::QueuedConnection, Q_ARG(QCameraFocus::FocusPointMode, mode)); + Q_D(QWinRTCameraFocusControl); + if (d->focusPointMode == mode) + return; + + if (!d->focusModeInitialized) { + d->focusPointMode = mode; + emit focusPointModeChanged(mode); + return; + } + QWinRTCameraControl *cameraControl = static_cast<QWinRTCameraControl *>(parent()); + Q_ASSERT(cameraControl); + if (!d->supportedFocusPointModes.contains(mode)) { + cameraControl->emitError(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera point focus mode.")); + return; + } + if (QCameraFocus::FocusPointCenter == mode || QCameraFocus::FocusPointAuto == mode) + d->focusPoint = QPointF(0.5, 0.5); + // Don't apply focus point focus settings if camera is in continuous focus mode + if (!d->focusModes.testFlag(QCameraFocus::ContinuousFocus)) { + changeFocusCustomPoint(d->focusPoint); + } else if (QCameraFocus::FocusPointCustom == mode) { + cameraControl->emitError(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera focus modes: ContinuousFocus with FocusPointCustom.")); + return; + } + d->focusPointMode = mode; + emit focusPointModeChanged(mode); } bool QWinRTCameraFocusControl::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const @@ -113,7 +172,20 @@ QPointF QWinRTCameraFocusControl::customFocusPoint() const void QWinRTCameraFocusControl::setCustomFocusPoint(const QPointF &point) { - QMetaObject::invokeMethod(this, "applyFocusCustomPoint", Qt::QueuedConnection, Q_ARG(const QPointF, point)); + Q_D(QWinRTCameraFocusControl); + if (d->focusPointMode != QCameraFocus::FocusPointCustom) { + QWinRTCameraControl *cameraControl = static_cast<QWinRTCameraControl *>(parent()); + Q_ASSERT(cameraControl); + cameraControl->emitError(QCamera::InvalidRequestError, QStringLiteral("Custom focus point can be set only in FocusPointCustom focus mode.")); + return; + } + if (d->focusPoint == point) + return; + if (changeFocusCustomPoint(point)) { + d->focusPoint = point; + emit customFocusPointChanged(point); + } + } QCameraFocusZoneList QWinRTCameraFocusControl::focusZones() const @@ -176,92 +248,6 @@ void QWinRTCameraFocusControl::imageCaptureQueueChanged(bool isEmpty) d->imageCaptureIdle = isEmpty; } -void QWinRTCameraFocusControl::applyFocusCustomPoint(const QPointF &point) -{ - Q_D(QWinRTCameraFocusControl); - if (d->focusPointMode != QCameraFocus::FocusPointCustom) { - QWinRTCameraControl *cameraControl = static_cast<QWinRTCameraControl *>(parent()); - Q_ASSERT(cameraControl); - cameraControl->emitError(QCamera::InvalidRequestError, QStringLiteral("Custom focus point can be set only in FocusPointCustom focus mode.")); - return; - } - if (d->focusPoint == point) - return; - if (changeFocusCustomPoint(point)) { - d->focusPoint = point; - emit customFocusPointChanged(point); - } -} - -void QWinRTCameraFocusControl::applyFocusMode(QCameraFocus::FocusModes modes) -{ - Q_D(QWinRTCameraFocusControl); - if (d->focusModes == modes) - return; - QWinRTCameraControl *cameraControl = static_cast<QWinRTCameraControl *>(parent()); - Q_ASSERT(cameraControl); - if (!modes) { - cameraControl->emitError(QCamera::InvalidRequestError, QStringLiteral("Can't set empty camera focus modes.")); - return; - } - if (!d->focusModeInitialized) { - d->focusModes = modes; - emit focusModeChanged(modes); - return; - } - if (!isFocusModeSupported(modes)) { - cameraControl->emitError(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera focus modes.")); - return; - } - if (modes.testFlag(QCameraFocus::ContinuousFocus)) { - if (QCameraFocus::FocusPointCustom == d->focusPointMode) { - cameraControl->emitError(QCamera::NotSupportedFeatureError, - QStringLiteral("Unsupported camera focus modes: ContinuousFocus with FocusPointCustom.")); - return; - } else if (!d->imageCaptureIdle) { - cameraControl->emitError(QCamera::NotSupportedFeatureError, - QStringLiteral("Can't set ContinuousFocus camera focus mode while capturing image.")); - return; - } - } - if (!cameraControl->setFocus(modes)) - return; - if (modes.testFlag(QCameraFocus::ContinuousFocus) || d->focusModes.testFlag(QCameraFocus::ContinuousFocus)) - cameraControl->focus(); - d->focusModes = modes; - emit focusModeChanged(modes); -} - -void QWinRTCameraFocusControl::applyFocusPointMode(QCameraFocus::FocusPointMode mode) -{ - Q_D(QWinRTCameraFocusControl); - if (d->focusPointMode == mode) - return; - - if (!d->focusModeInitialized) { - d->focusPointMode = mode; - emit focusPointModeChanged(mode); - return; - } - QWinRTCameraControl *cameraControl = static_cast<QWinRTCameraControl *>(parent()); - Q_ASSERT(cameraControl); - if (!d->supportedFocusPointModes.contains(mode)) { - cameraControl->emitError(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera point focus mode.")); - return; - } - if (QCameraFocus::FocusPointCenter == mode || QCameraFocus::FocusPointAuto == mode) - d->focusPoint = QPointF(0.5, 0.5); - // Don't apply focus point focus settings if camera is in continuous focus mode - if (!d->focusModes.testFlag(QCameraFocus::ContinuousFocus)) { - changeFocusCustomPoint(d->focusPoint); - } else if (QCameraFocus::FocusPointCustom == mode) { - cameraControl->emitError(QCamera::NotSupportedFeatureError, QStringLiteral("Unsupported camera focus modes: ContinuousFocus with FocusPointCustom.")); - return; - } - d->focusPointMode = mode; - emit focusPointModeChanged(mode); -} - bool QWinRTCameraFocusControl::changeFocusCustomPoint(const QPointF &point) { Q_D(QWinRTCameraFocusControl); diff --git a/src/plugins/winrt/qwinrtcamerafocuscontrol.h b/src/plugins/winrt/qwinrtcamerafocuscontrol.h index 6ec2ea67a..0a8c0afcf 100644 --- a/src/plugins/winrt/qwinrtcamerafocuscontrol.h +++ b/src/plugins/winrt/qwinrtcamerafocuscontrol.h @@ -68,9 +68,6 @@ private slots: void imageCaptureQueueChanged(bool isEmpty); private: - Q_INVOKABLE void applyFocusCustomPoint(const QPointF &point); - Q_INVOKABLE void applyFocusMode(QCameraFocus::FocusModes modes); - Q_INVOKABLE void applyFocusPointMode(QCameraFocus::FocusPointMode mode); bool changeFocusCustomPoint(const QPointF &point); QScopedPointer<QWinRTCameraFocusControlPrivate> d_ptr; diff --git a/src/plugins/winrt/qwinrtcameraservice.cpp b/src/plugins/winrt/qwinrtcameraservice.cpp index f76edae51..d0327a708 100644 --- a/src/plugins/winrt/qwinrtcameraservice.cpp +++ b/src/plugins/winrt/qwinrtcameraservice.cpp @@ -50,6 +50,7 @@ #include <QtMultimedia/QVideoRendererControl> #include <QtMultimedia/QVideoDeviceSelectorControl> #include <QtMultimedia/QImageEncoderControl> +#include <QtMultimedia/QCameraFlashControl> #include <QtMultimedia/QCameraFocusControl> #include <QtMultimedia/QCameraLocksControl> #include <QtMultimedia/QMediaVideoProbeControl> @@ -98,6 +99,9 @@ QMediaControl *QWinRTCameraService::requestControl(const char *name) if (qstrcmp(name, QImageEncoderControl_iid) == 0) return d->cameraControl->imageEncoderControl(); + if (qstrcmp(name, QCameraFlashControl_iid) == 0) + return d->cameraControl->cameraFlashControl(); + if (qstrcmp(name, QCameraFocusControl_iid) == 0) return d->cameraControl->cameraFocusControl(); diff --git a/src/plugins/winrt/winrt.pro b/src/plugins/winrt/winrt.pro index 87e44cce2..940064f46 100644 --- a/src/plugins/winrt/winrt.pro +++ b/src/plugins/winrt/winrt.pro @@ -6,6 +6,7 @@ LIBS += -lmfplat -lmfuuid -loleaut32 -ld3d11 -lruntimeobject HEADERS += \ qwinrtabstractvideorenderercontrol.h \ qwinrtcameracontrol.h \ + qwinrtcameraflashcontrol.h \ qwinrtcamerafocuscontrol.h \ qwinrtcameraimagecapturecontrol.h \ qwinrtcamerainfocontrol.h \ @@ -23,6 +24,7 @@ HEADERS += \ SOURCES += \ qwinrtabstractvideorenderercontrol.cpp \ qwinrtcameracontrol.cpp \ + qwinrtcameraflashcontrol.cpp \ qwinrtcamerafocuscontrol.cpp \ qwinrtcameraimagecapturecontrol.cpp \ qwinrtcamerainfocontrol.cpp \ |