From 57b1dc867cc29e0a7fb28ee6701cfa3e1b2257d2 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Fri, 12 Aug 2016 11:09:56 +0200 Subject: Doc: Change instances of 'OS X' to 'macOS' As of version 10.12 (Sierra), the name of Apple's desktop operating system will be macOS. Change all occurrences where the platform is discussed to use the macro \macos (defined in the documentation configuration in qtbase). Change-Id: I1ba3b1e3c11870523516d3a13790d40dd0803aad Reviewed-by: Leena Miettinen --- src/multimedia/audio/qaudiosystemplugin.cpp | 2 +- src/multimedia/doc/src/qtmultimedia-examples.qdoc | 2 +- src/multimedia/video/qabstractvideobuffer.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/multimedia/audio/qaudiosystemplugin.cpp b/src/multimedia/audio/qaudiosystemplugin.cpp index de719fceb..02e1eead2 100644 --- a/src/multimedia/audio/qaudiosystemplugin.cpp +++ b/src/multimedia/audio/qaudiosystemplugin.cpp @@ -66,7 +66,7 @@ QAudioSystemFactoryInterface::~QAudioSystemFactoryInterface() \sa QAbstractAudioDeviceInfo, QAbstractAudioOutput, QAbstractAudioInput - Qt supports win32, linux(alsa) and OS X standard (builtin to the + Qt supports win32, linux(alsa) and \macos standard (builtin to the QtMultimedia library at compile time). You can support other backends other than these predefined ones by diff --git a/src/multimedia/doc/src/qtmultimedia-examples.qdoc b/src/multimedia/doc/src/qtmultimedia-examples.qdoc index 582efc5e1..dd35aeb1a 100644 --- a/src/multimedia/doc/src/qtmultimedia-examples.qdoc +++ b/src/multimedia/doc/src/qtmultimedia-examples.qdoc @@ -32,6 +32,6 @@ \brief Demonstrates the multimedia functionality provided by Qt. The \l{Qt Multimedia} module provides low-level audio support on Linux, - Windows and OS X. It also provides audio plugin API to allow developers + Windows and \macos. It also provides audio plugin API to allow developers implement their own audio support for custom devices and platforms. */ diff --git a/src/multimedia/video/qabstractvideobuffer.cpp b/src/multimedia/video/qabstractvideobuffer.cpp index 6dca8dad8..b7f7db805 100644 --- a/src/multimedia/video/qabstractvideobuffer.cpp +++ b/src/multimedia/video/qabstractvideobuffer.cpp @@ -92,7 +92,7 @@ int QAbstractVideoBufferPrivate::map( \value NoHandle The buffer has no handle, its data can only be accessed by mapping the buffer. \value GLTextureHandle The handle of the buffer is an OpenGL texture ID. \value XvShmImageHandle The handle contains pointer to shared memory XVideo image. - \value CoreImageHandle The handle contains pointer to OS X CIImage. + \value CoreImageHandle The handle contains pointer to \macos CIImage. \value QPixmapHandle The handle of the buffer is a QPixmap. \value EGLImageHandle The handle of the buffer is an EGLImageKHR. \value UserHandle Start value for user defined handle types. -- cgit v1.2.3 From c7ae48c5fb5005efae05f2cabdeee7117f6f72fa Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 20 Jul 2016 13:09:39 +0200 Subject: PulseAudio: flush stream before loading a new source in a sound effect When loading a new QSoundEffect source, the data in the stream must be flushed to avoid that the old source plays right before the new one. Task-number: QTBUG-48982 Change-Id: Iff14884edb2fb4851f93e67ff8191b77ebb16359 Reviewed-by: Christian Stromme --- src/multimedia/audio/qsoundeffect_pulse_p.cpp | 45 ++++++++++++++++++++++----- src/multimedia/audio/qsoundeffect_pulse_p.h | 10 ++++-- 2 files changed, 45 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.cpp b/src/multimedia/audio/qsoundeffect_pulse_p.cpp index 43d4a6cb0..48f3333c2 100644 --- a/src/multimedia/audio/qsoundeffect_pulse_p.cpp +++ b/src/multimedia/audio/qsoundeffect_pulse_p.cpp @@ -413,7 +413,13 @@ void QSoundEffectPrivate::setSource(const QUrl &url) #ifdef QT_PA_DEBUG qDebug() << this << "setSource =" << url; #endif + + // Make sure the stream is empty before loading a new source (otherwise whatever is there will + // be played before the new source) + emptyStream(); + stop(); + if (m_sample) { if (!m_sampleReady) { disconnect(m_sample, SIGNAL(error()), this, SLOT(decoderError())); @@ -588,7 +594,7 @@ void QSoundEffectPrivate::playAvailable() setLoopsRemaining(0); m_playQueued = true; Q_ASSERT(m_pulseStream); - emptyStream(); + emptyStream(ReloadSampleWhenDone); return; } setLoopsRemaining(m_loopCount); @@ -598,18 +604,25 @@ void QSoundEffectPrivate::playAvailable() setPlaying(true); } -void QSoundEffectPrivate::emptyStream() +void QSoundEffectPrivate::emptyStream(EmptyStreamOptions options) { #ifdef QT_PA_DEBUG qDebug() << this << "emptyStream"; #endif + if (!m_pulseStream || m_emptying) + return; + + const bool reloadSample = options.testFlag(ReloadSampleWhenDone); + pa_stream_success_cb_t flushCompleteCb = reloadSample ? stream_flush_reload_callback + : stream_flush_callback; + m_emptying = true; pa_stream_set_write_callback(m_pulseStream, 0, 0); pa_stream_set_underflow_callback(m_pulseStream, 0, 0); - pa_operation_unref(pa_stream_flush(m_pulseStream, stream_flush_callback, m_ref->getRef())); + pa_operation_unref(pa_stream_flush(m_pulseStream, flushCompleteCb, m_ref->getRef())); } -void QSoundEffectPrivate::emptyComplete(void *stream) +void QSoundEffectPrivate::emptyComplete(void *stream, bool reload) { PulseDaemonLocker locker; #ifdef QT_PA_DEBUG @@ -619,7 +632,7 @@ void QSoundEffectPrivate::emptyComplete(void *stream) m_emptying = false; if ((pa_stream *)stream == m_pulseStream) - pa_operation_unref(pa_stream_cork(m_pulseStream, 1, stream_cork_callback, m_ref->getRef())); + pa_operation_unref(pa_stream_cork(m_pulseStream, 1, reload ? stream_cork_callback : 0, m_ref->getRef())); } void QSoundEffectPrivate::sampleReady() @@ -851,7 +864,7 @@ void QSoundEffectPrivate::stop() PulseDaemonLocker locker; m_stopping = true; if (m_pulseStream) { - emptyStream(); + emptyStream(ReloadSampleWhenDone); if (m_reloadCategory) { unloadPulseStream(); // upon play we reconnect anyway } @@ -1094,10 +1107,26 @@ void QSoundEffectPrivate::stream_flush_callback(pa_stream *s, int success, void if (!success) qWarning("QSoundEffect(pulseaudio): faild to drain"); + + QMetaObject::invokeMethod(self, "emptyComplete", Qt::QueuedConnection, Q_ARG(void*, s), Q_ARG(bool, false)); +} + +void QSoundEffectPrivate::stream_flush_reload_callback(pa_stream *s, int success, void *userdata) +{ #ifdef QT_PA_DEBUG - qDebug() << self << "stream_flush_callback"; + qDebug() << "stream_flush_reload_callback"; #endif - QMetaObject::invokeMethod(self, "emptyComplete", Qt::QueuedConnection, Q_ARG(void*, s)); + Q_UNUSED(s); + QSoundEffectRef *ref = reinterpret_cast(userdata); + QSoundEffectPrivate *self = ref->soundEffect(); + ref->release(); + if (!self) + return; + + if (!success) + qWarning("QSoundEffect(pulseaudio): faild to drain"); + + QMetaObject::invokeMethod(self, "emptyComplete", Qt::QueuedConnection, Q_ARG(void*, s), Q_ARG(bool, true)); } void QSoundEffectPrivate::stream_write_done_callback(void *p) diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.h b/src/multimedia/audio/qsoundeffect_pulse_p.h index 0f16b98a2..2eb20695a 100644 --- a/src/multimedia/audio/qsoundeffect_pulse_p.h +++ b/src/multimedia/audio/qsoundeffect_pulse_p.h @@ -111,7 +111,7 @@ private Q_SLOTS: void underRun(); void prepare(); void streamReady(); - void emptyComplete(void *stream); + void emptyComplete(void *stream, bool reload); void handleAvailabilityChanged(bool available); @@ -119,7 +119,12 @@ private: void playAvailable(); void playSample(); - void emptyStream(); + enum EmptyStreamOption { + ReloadSampleWhenDone = 0x1 + }; + Q_DECLARE_FLAGS(EmptyStreamOptions, EmptyStreamOption) + void emptyStream(EmptyStreamOptions options = EmptyStreamOptions()); + void createPulseStream(); void unloadPulseStream(); @@ -134,6 +139,7 @@ private: static void stream_underrun_callback(pa_stream *s, void *userdata); static void stream_cork_callback(pa_stream *s, int success, void *userdata); static void stream_flush_callback(pa_stream *s, int success, void *userdata); + static void stream_flush_reload_callback(pa_stream *s, int success, void *userdata); static void stream_write_done_callback(void *p); static void stream_adjust_prebuffer_callback(pa_stream *s, int success, void *userdata); static void stream_reset_buffer_callback(pa_stream *s, int success, void *userdata); -- cgit v1.2.3 From c9de25fa342ff8066d49541179c30d0ce45950b4 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 20 Jul 2016 13:15:20 +0200 Subject: PulseAudio (QSoundEffect): don't write data to an unready stream The PulseAudio stream must be ready to write data to it, otherwise an assert is raised. Change-Id: Iaa108124a135b018aa84845a37665895a005f380 Reviewed-by: Christian Stromme --- src/multimedia/audio/qsoundeffect_pulse_p.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.cpp b/src/multimedia/audio/qsoundeffect_pulse_p.cpp index 48f3333c2..1fb10d121 100644 --- a/src/multimedia/audio/qsoundeffect_pulse_p.cpp +++ b/src/multimedia/audio/qsoundeffect_pulse_p.cpp @@ -736,6 +736,10 @@ void QSoundEffectPrivate::prepare() if (!m_pulseStream || !m_sampleReady) return; PulseDaemonLocker locker; + + if (pa_stream_get_state(m_pulseStream) != PA_STREAM_READY) + return; + pa_stream_set_write_callback(m_pulseStream, stream_write_callback, this); pa_stream_set_underflow_callback(m_pulseStream, stream_underrun_callback, this); m_stopping = false; -- cgit v1.2.3 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') 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 cc12446728d00161116d6e1823e161440415d2d5 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 8 Jul 2016 15:22:16 +0200 Subject: Improve audio volume documentation Added information about volume scales. Change-Id: Ica8367396147e3e1c814b3575faa5cf0503be031 Reviewed-by: Venugopal Shivashankar Reviewed-by: Christian Stromme --- src/imports/multimedia/Video.qml | 12 ++++++++++- src/imports/multimedia/qdeclarativeaudio.cpp | 24 ++++++++++++++++++---- src/multimedia/audio/qaudioinput.cpp | 7 ++++++- src/multimedia/audio/qaudiooutput.cpp | 13 ++++++++++-- src/multimedia/audio/qsoundeffect.cpp | 25 ++++++++++++++++++++--- src/multimedia/controls/qmediaplayercontrol.cpp | 2 ++ src/multimedia/controls/qmediarecordercontrol.cpp | 6 ++++-- src/multimedia/playback/qmediaplayer.cpp | 10 +++++++-- src/multimedia/recording/qmediarecorder.cpp | 11 +++++++++- 9 files changed, 94 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/imports/multimedia/Video.qml b/src/imports/multimedia/Video.qml index 2188d17b9..b3fee7495 100644 --- a/src/imports/multimedia/Video.qml +++ b/src/imports/multimedia/Video.qml @@ -360,7 +360,17 @@ Item { /*! \qmlproperty real Video::volume - This property holds the volume of the audio output, from 0.0 (silent) to 1.0 (maximum volume). + This property holds the audio volume. + + The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside + this range will be clamped. + + The default volume is \c 1.0. + + UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic + scale will produce linear changes in perceived loudness, which is what a user would normally + expect from a volume control. See \l {QtMultimedia::QtMultimedia::convertVolume()}{QtMultimedia.convertVolume()} + for more details. */ property alias volume: player.volume diff --git a/src/imports/multimedia/qdeclarativeaudio.cpp b/src/imports/multimedia/qdeclarativeaudio.cpp index 86f8f30ba..5a065072c 100644 --- a/src/imports/multimedia/qdeclarativeaudio.cpp +++ b/src/imports/multimedia/qdeclarativeaudio.cpp @@ -689,9 +689,17 @@ QDeclarativeAudio::PlaybackState QDeclarativeAudio::playbackState() const /*! \qmlproperty real QtMultimedia::Audio::volume - This property holds the volume of the audio output, from 0.0 (silent) to 1.0 (maximum volume). + This property holds the audio volume. - Defaults to 1.0. + The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this + range will be clamped. + + The default volume is \c 1.0. + + UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale + will produce linear changes in perceived loudness, which is what a user would normally expect + from a volume control. See \l {QtMultimedia::QtMultimedia::convertVolume()}{QtMultimedia.convertVolume()} + for more details. */ /*! @@ -1310,9 +1318,17 @@ void QDeclarativeAudio::_q_mediaChanged(const QMediaContent &media) /*! \qmlproperty real QtMultimedia::MediaPlayer::volume - This property holds the volume of the audio output, from 0.0 (silent) to 1.0 (maximum volume). + This property holds the audio volume of the media player. - Defaults to 1.0. + The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this + range will be clamped. + + The default volume is \c 1.0. + + UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale + will produce linear changes in perceived loudness, which is what a user would normally expect + from a volume control. See \l {QtMultimedia::QtMultimedia::convertVolume()}{QtMultimedia.convertVolume()} + for more details. */ /*! diff --git a/src/multimedia/audio/qaudioinput.cpp b/src/multimedia/audio/qaudioinput.cpp index bc6b6215b..ad54521fa 100644 --- a/src/multimedia/audio/qaudioinput.cpp +++ b/src/multimedia/audio/qaudioinput.cpp @@ -330,10 +330,15 @@ int QAudioInput::notifyInterval() const /*! Sets the input volume to \a volume. + The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this + range will be clamped. + If the device does not support adjusting the input volume then \a volume will be ignored and the input volume will remain at 1.0. + The default volume is \c 1.0. + Note: Adjustments to the volume will change the volume of this audio stream, not the global volume. */ void QAudioInput::setVolume(qreal volume) @@ -342,7 +347,7 @@ void QAudioInput::setVolume(qreal volume) } /*! - Returns the input volume (gain). + Returns the input volume. If the device does not support adjusting the input volume the returned value will be 1.0. diff --git a/src/multimedia/audio/qaudiooutput.cpp b/src/multimedia/audio/qaudiooutput.cpp index 585855ace..670dca7bc 100644 --- a/src/multimedia/audio/qaudiooutput.cpp +++ b/src/multimedia/audio/qaudiooutput.cpp @@ -349,9 +349,18 @@ QAudio::State QAudioOutput::state() const } /*! - Sets the volume. - Where \a volume is between 0.0 and 1.0 inclusive. + Sets the output volume to \a volume. + + The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this + range will be clamped. + + The default volume is \c 1.0. + Note: Adjustments to the volume will change the volume of this audio stream, not the global volume. + + UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale + will produce linear changes in perceived loudness, which is what a user would normally expect + from a volume control. See QAudio::convertVolume() for more details. */ void QAudioOutput::setVolume(qreal volume) { diff --git a/src/multimedia/audio/qsoundeffect.cpp b/src/multimedia/audio/qsoundeffect.cpp index f653de86e..d3b818073 100644 --- a/src/multimedia/audio/qsoundeffect.cpp +++ b/src/multimedia/audio/qsoundeffect.cpp @@ -258,12 +258,22 @@ int QSoundEffect::loopsRemaining() const /*! \qmlproperty qreal QtMultimedia::SoundEffect::volume - This property holds the volume of the sound effect playback, from 0.0 (silent) to 1.0 (maximum volume). + This property holds the volume of the sound effect playback. + + The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this + range will be clamped. + + The default volume is \c 1.0. + + UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale + will produce linear changes in perceived loudness, which is what a user would normally expect + from a volume control. See \l {QtMultimedia::QtMultimedia::convertVolume()}{QtMultimedia.convertVolume()} + for more details. */ /*! \property QSoundEffect::volume - This property holds the volume of the sound effect playback, from 0.0 (silent) to 1.0 (maximum volume). + This property holds the volume of the sound effect playback, from 0.0 (silence) to 1.0 (full volume). */ /*! @@ -275,7 +285,16 @@ qreal QSoundEffect::volume() const } /*! - Sets the volume to play the sound effect at to \a volume, from 0.0 (silent) to 1.0 (maximum volume). + Sets the sound effect volume to \a volume. + + The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this + range will be clamped. + + The default volume is \c 1.0. + + UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale + will produce linear changes in perceived loudness, which is what a user would normally expect + from a volume control. See QAudio::convertVolume() for more details. */ void QSoundEffect::setVolume(qreal volume) { diff --git a/src/multimedia/controls/qmediaplayercontrol.cpp b/src/multimedia/controls/qmediaplayercontrol.cpp index cd56dffcb..46de05b51 100644 --- a/src/multimedia/controls/qmediaplayercontrol.cpp +++ b/src/multimedia/controls/qmediaplayercontrol.cpp @@ -175,6 +175,8 @@ QMediaPlayerControl::QMediaPlayerControl(QObject *parent): \fn QMediaPlayerControl::setVolume(int volume) Sets the audio \a volume of a player control. + + The volume is scaled linearly, ranging from \c 0 (silence) to \c 100 (full volume). */ /*! diff --git a/src/multimedia/controls/qmediarecordercontrol.cpp b/src/multimedia/controls/qmediarecordercontrol.cpp index 4654d16eb..611f1fdcc 100644 --- a/src/multimedia/controls/qmediarecordercontrol.cpp +++ b/src/multimedia/controls/qmediarecordercontrol.cpp @@ -160,13 +160,15 @@ QMediaRecorderControl::~QMediaRecorderControl() /*! \fn qreal QMediaRecorderControl::volume() const - Returns the linear audio gain of media recorder. + Returns the audio volume of a media recorder control. */ /*! \fn void QMediaRecorderControl::setVolume(qreal gain) - Sets the linear audio \a gain of a media recorder. + Sets the audio \a volume of a media recorder control. + + The volume is scaled linearly, ranging from \c 0 (silence) to \c 100 (full volume). */ /*! diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp index c5261921a..648c13220 100644 --- a/src/multimedia/playback/qmediaplayer.cpp +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -1372,8 +1372,14 @@ QList QMediaPlayer::supportedAudioRoles() const \property QMediaPlayer::volume \brief the current playback volume. - The playback volume is linear in effect and the value can range from 0 - - 100, values outside this range will be clamped. + The playback volume is scaled linearly, ranging from \c 0 (silence) to \c 100 (full volume). + Values outside this range will be clamped. + + By default the volume is \c 100. + + UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale + will produce linear changes in perceived loudness, which is what a user would normally expect + from a volume control. See QAudio::convertVolume() for more details. */ /*! diff --git a/src/multimedia/recording/qmediarecorder.cpp b/src/multimedia/recording/qmediarecorder.cpp index a5f4c15ce..7b0234988 100644 --- a/src/multimedia/recording/qmediarecorder.cpp +++ b/src/multimedia/recording/qmediarecorder.cpp @@ -556,7 +556,16 @@ void QMediaRecorder::setMuted(bool muted) /*! \property QMediaRecorder::volume - \brief the linear audio gain of media recorder. + \brief the current recording audio volume. + + The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this + range will be clamped. + + The default volume is \c 1.0. + + UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale + will produce linear changes in perceived loudness, which is what a user would normally expect + from a volume control. See QAudio::convertVolume() for more details. */ qreal QMediaRecorder::volume() const -- 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') 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') 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') 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') 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') 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') 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') 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 From 29232a2bc207fb7dc44532f64bbe35d9181340c6 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 26 Aug 2016 11:58:48 +0200 Subject: Improve robustness of QML plugin loading Use a variable that expands to the latest plugin version instead of hard-coding the string. Change-Id: I3bdbee161e4a3b59127dc4f00a0c9ce9386b67c2 Reviewed-by: Yoann Lopes --- src/imports/audioengine/audioengine.cpp | 2 +- src/imports/multimedia/multimedia.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/imports/audioengine/audioengine.cpp b/src/imports/audioengine/audioengine.cpp index 8eb2dea33..a132af49a 100644 --- a/src/imports/audioengine/audioengine.cpp +++ b/src/imports/audioengine/audioengine.cpp @@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE class QAudioEngineDeclarativeModule : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QAudioEngineDeclarativeModule(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } diff --git a/src/imports/multimedia/multimedia.cpp b/src/imports/multimedia/multimedia.cpp index 872b2ae61..2a5e8cd2c 100644 --- a/src/imports/multimedia/multimedia.cpp +++ b/src/imports/multimedia/multimedia.cpp @@ -81,7 +81,7 @@ static QObject *multimedia_global_object(QQmlEngine *qmlEngine, QJSEngine *jsEng class QMultimediaDeclarativeModule : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QMultimediaDeclarativeModule(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } -- cgit v1.2.3 From 6817067ff72c4493ab39fd065c9382568da06378 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 18 Aug 2016 14:18:59 +0200 Subject: Optimize QMediaPlaylistPrivate::readItems() When reading playlist items from a file, pass them to the playlist backend all at once rather than one by one. This might be faster depending on the implementation. Task-number: QTBUG-54849 Change-Id: I57acdc68604ee56fe5d7615ba0a72655e668443f Reviewed-by: Christian Stromme --- src/multimedia/playback/qmediaplaylist.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/multimedia/playback/qmediaplaylist.cpp b/src/multimedia/playback/qmediaplaylist.cpp index c63340637..7246d2adc 100644 --- a/src/multimedia/playback/qmediaplaylist.cpp +++ b/src/multimedia/playback/qmediaplaylist.cpp @@ -428,10 +428,12 @@ bool QMediaPlaylist::clear() bool QMediaPlaylistPrivate::readItems(QMediaPlaylistReader *reader) { + QList items; + while (!reader->atEnd()) - playlist()->addMedia(reader->readItem()); + items.append(reader->readItem()); - return true; + return playlist()->addMedia(items); } bool QMediaPlaylistPrivate::writeItems(QMediaPlaylistWriter *writer) -- cgit v1.2.3 From a8fe4b989b2002d3fcb4e33afe16bd6fd2ff192b Mon Sep 17 00:00:00 2001 From: Jochen Seemann Date: Wed, 31 Aug 2016 21:15:50 +0200 Subject: fix documentation for QML Playlist Some signals for QDeclarativePlaylist were wrongly tagged to QDeclarativeAudio. Task-number: QTBUG-55007 Change-Id: I16185f74768b45115f19c049ec1261d1d3dadf5c Reviewed-by: Yoann Lopes --- src/imports/multimedia/qdeclarativeplaylist.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/imports/multimedia/qdeclarativeplaylist.cpp b/src/imports/multimedia/qdeclarativeplaylist.cpp index bb785aa98..19413dec8 100644 --- a/src/imports/multimedia/qdeclarativeplaylist.cpp +++ b/src/imports/multimedia/qdeclarativeplaylist.cpp @@ -517,7 +517,7 @@ void QDeclarativePlaylist::componentComplete() } /*! - \qmlsignal QtMultimedia::Audio::itemAboutToBeInserted(start, end) + \qmlsignal QtMultimedia::Playlist::itemAboutToBeInserted(start, end) This signal is emitted when items are to be inserted into the playlist at \a start and ending at \a end. @@ -526,7 +526,7 @@ void QDeclarativePlaylist::componentComplete() */ /*! - \qmlsignal QtMultimedia::Audio::itemInserted(start, end) + \qmlsignal QtMultimedia::Playlist::itemInserted(start, end) This signal is emitted after items have been inserted into the playlist. The new items are those between \a start and \a end inclusive. @@ -535,7 +535,7 @@ void QDeclarativePlaylist::componentComplete() */ /*! - \qmlsignal QtMultimedia::Audio::itemAboutToBeRemoved(start, end) + \qmlsignal QtMultimedia::Playlist::itemAboutToBeRemoved(start, end) This signal emitted when items are to be deleted from the playlist at \a start and ending at \a end. @@ -544,7 +544,7 @@ void QDeclarativePlaylist::componentComplete() */ /*! - \qmlsignal QtMultimedia::Audio::itemRemoved(start, end) + \qmlsignal QtMultimedia::Playlist::itemRemoved(start, end) This signal is emitted after items have been removed from the playlist. The removed items are those between \a start and \a end inclusive. @@ -553,7 +553,7 @@ void QDeclarativePlaylist::componentComplete() */ /*! - \qmlsignal QtMultimedia::Audio::itemChanged(start, end) + \qmlsignal QtMultimedia::Playlist::itemChanged(start, end) This signal is emitted after items have been changed in the playlist between \a start and \a end positions inclusive. @@ -562,7 +562,7 @@ void QDeclarativePlaylist::componentComplete() */ /*! - \qmlsignal QtMultimedia::Audio::loaded() + \qmlsignal QtMultimedia::Playlist::loaded() This signal is emitted when the playlist loading succeeded. @@ -570,7 +570,7 @@ void QDeclarativePlaylist::componentComplete() */ /*! - \qmlsignal QtMultimedia::Audio::loadFailed() + \qmlsignal QtMultimedia::Playlist::loadFailed() This signal is emitted when the playlist loading failed. \l error and \l errorString can be checked for more information on the failure. -- cgit v1.2.3 From af985a697a47cc887625e06c05f5cb785ee66d35 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Fri, 2 Sep 2016 11:01:29 +0200 Subject: winrt: Fix QAudioDeviceInfo::default*Device to return name instead id 3c5bbb0dac7bed3199ddddc88c0175d5a2ac1036 added the default* functions to query a default device. However, IMediaDeviceStatics can only return ids and not the device names. Hence we need to invoke availableDevices to create the internal mapping and return the device name to properly initialize audio devices afterwards. Task-number: QTBUG-55631 Change-Id: I38b9205a933de5e41296a2e5880d0379db41ad97 Reviewed-by: Oliver Wolff --- src/plugins/wasapi/qwasapiutils.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') 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 &deviceNames = mode == QAudio::AudioInput ? gMapping->inputDeviceNames : gMapping->outputDeviceNames; + QList &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 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 QWasapiUtils::availableDevices(QAudio::Mode mode) -- cgit v1.2.3 From f92874545bbe79fa72eed773dabc49d109b7b6ca Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Mon, 12 Sep 2016 16:00:17 +0200 Subject: wasapi: Fix thread affinity It is expected from the user side that the QIODevice passed to the audio input/output is handled in the very same thread it has been created in. Previously we used the worker thread for it. Instead, schedule handling a buffer to the GUI thread and move on. This also helps simplifying many of the emits, as they happen in the same thread as the target device. Task-number: QTBUG-55894 Change-Id: I552a7a41562dccbaae5681e3c416267165720d30 Reviewed-by: Oliver Wolff --- src/plugins/wasapi/qwasapiaudioinput.cpp | 121 +++++++++++++++--------------- src/plugins/wasapi/qwasapiaudioinput.h | 3 + src/plugins/wasapi/qwasapiaudiooutput.cpp | 86 +++++++++++---------- src/plugins/wasapi/qwasapiaudiooutput.h | 3 + 4 files changed, 113 insertions(+), 100 deletions(-) (limited to 'src') 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(buffer), writeBytes); + const qint64 written = m_eventDevice->write(reinterpret_cast(buffer), writeBytes); - if (Q_UNLIKELY(flags & AUDCLNT_BUFFERFLAGS_SILENT)) - delete [] buffer; + if (Q_UNLIKELY(flags & AUDCLNT_BUFFERFLAGS_SILENT)) + delete [] buffer; - if (written < static_cast(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(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(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(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; }; -- cgit v1.2.3 From 462ed1af764603e1422664e51f4d83ded3fec7d1 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Fri, 2 Sep 2016 12:04:06 +0200 Subject: wasapi: fix typo for supported rates Task-number: QTBUG-55630 Change-Id: I2f5defd78fbdd57e6121dde0287b615f7db8848b Reviewed-by: Oliver Wolff --- src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') 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); -- cgit v1.2.3 From 6e8f05f016726e078374f92092f643b5154855cf Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 7 Sep 2016 15:37:03 +0200 Subject: Update plugins.qmltypes for 5.8 Change-Id: Iade5ceb5f791abaa2ec7649ff4752d1b59d96aad Reviewed-by: Christian Stromme --- src/imports/multimedia/plugins.qmltypes | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/imports/multimedia/plugins.qmltypes b/src/imports/multimedia/plugins.qmltypes index 91fff02eb..20bbf7d3e 100644 --- a/src/imports/multimedia/plugins.qmltypes +++ b/src/imports/multimedia/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtMultimedia 5.7' +// 'qmlplugindump -nonrelocatable QtMultimedia 5.8' Module { dependencies: ["QtQuick 2.0"] @@ -1248,8 +1248,24 @@ Module { isCreatable: false isSingleton: true exportMetaObjectRevisions: [0] + Enum { + name: "VolumeScale" + values: { + "LinearVolumeScale": 0, + "CubicVolumeScale": 1, + "LogarithmicVolumeScale": 2, + "DecibelVolumeScale": 3 + } + } Property { name: "defaultCamera"; type: "QJSValue"; isReadonly: true } Property { name: "availableCameras"; type: "QJSValue"; isReadonly: true } + Method { + name: "convertVolume" + type: "double" + Parameter { name: "volume"; type: "double" } + Parameter { name: "from"; type: "VolumeScale" } + Parameter { name: "to"; type: "VolumeScale" } + } } Component { name: "QDeclarativePlaylist" @@ -1794,9 +1810,10 @@ Module { prototype: "QObject" exports: [ "QtMultimedia/SoundEffect 5.0", - "QtMultimedia/SoundEffect 5.3" + "QtMultimedia/SoundEffect 5.3", + "QtMultimedia/SoundEffect 5.8" ] - exportMetaObjectRevisions: [0, 0] + exportMetaObjectRevisions: [0, 0, 0] Enum { name: "Loop" values: { -- cgit v1.2.3 From f5a264d1f6dd5c6470c66573a3faeae58aac360f Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 7 Sep 2016 15:10:55 +0200 Subject: Register 5.8 version for the multimedia QML module There isn't any new API in 5.8, we need to re-register an existing type to make that version number available. Change-Id: I061dc53e9570eefc1cbdcb9d15f557904b5d275f Reviewed-by: Christian Stromme --- src/imports/multimedia/multimedia.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/imports/multimedia/multimedia.cpp b/src/imports/multimedia/multimedia.cpp index 2a5e8cd2c..b7ab473c7 100644 --- a/src/imports/multimedia/multimedia.cpp +++ b/src/imports/multimedia/multimedia.cpp @@ -140,6 +140,9 @@ public: qmlRegisterUncreatableType(uri, 5, 7, "CameraImageProcessing", trUtf8("CameraImageProcessing is provided by Camera")); + // 5.8 types (nothing new, re-register one of the types) + qmlRegisterType(uri, 5, 8, "SoundEffect"); + qmlRegisterType(); qmlRegisterType(); } -- cgit v1.2.3 From e2adbda766f5fbdc6238cbd6bc64a6d3383c844e Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 6 Sep 2016 16:57:09 +0200 Subject: DirectShow: support MJPEG cameras Map MEDIASUBTYPE_MJPG to QVideoFrame::Format_Jpeg, which makes sure that cameras that only support MJPEG are configured properly. Task-number: QTBUG-55359 Change-Id: I732c56afc51109aba0231c8537f795e8d276c194 Reviewed-by: Christian Stromme --- src/plugins/directshow/camera/dscamerasession.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index 1cb91cd4a..5df2d2fb3 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -168,6 +168,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) -- cgit v1.2.3 From 5fd362251cab222eacab61baece43b0ac2055c46 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 16 Sep 2016 10:18:25 +0200 Subject: Fix compilation after feature modularization in qtbase Change-Id: I7449a68cfb76798e9c4e3101da4a4e3ab713d4be Reviewed-by: Friedemann Kleint --- src/plugins/videonode/videonode.pro | 1 + 1 file changed, 1 insertion(+) (limited to 'src') 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 -- cgit v1.2.3 From 3c893cc4ef799f987638e56ef43f1ac5cbe0c249 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Thu, 15 Sep 2016 08:56:41 +0200 Subject: winrt: Make focus actions synchronous The camera and its controls have been moved out of the xaml thread recently, hence acting asynchronously is not required anymore for the focus control. In addition to this, previous behavior caused troubles inside QML as QDeclarativeCameraFocus::setFocusMode always emitted a focus change even though it did not happen yet. This resulted in inconsistencies between QML and the plugin. Task-number: QTBUG-48539 Change-Id: I19a3a3512530b01b627476e233291d737cfee11f Reviewed-by: Friedemann Kleint Reviewed-by: Samuel Nevala Reviewed-by: Oliver Wolff --- src/plugins/winrt/qwinrtcamerafocuscontrol.cpp | 164 +++++++++++-------------- src/plugins/winrt/qwinrtcamerafocuscontrol.h | 3 - 2 files changed, 75 insertions(+), 92 deletions(-) (limited to 'src') 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(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(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(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(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(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(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 d_ptr; -- cgit v1.2.3 From 0f47f44d2fc7b3fac7fdd8ee6eeafd767c43ec2e Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Tue, 19 Apr 2016 09:52:20 +0200 Subject: winrt: Add QCameraFlashControl This is without video modes so far, simply because video itself is not supported yet. Also included a cleanup for string conversions. Task-number: QTBUG-48541 Change-Id: Ib090f61861596e095d597cf7e5e74f7040fbc58f Reviewed-by: Oliver Wolff --- src/plugins/winrt/qwinrtcameracontrol.cpp | 11 ++ src/plugins/winrt/qwinrtcameracontrol.h | 2 + src/plugins/winrt/qwinrtcameraflashcontrol.cpp | 191 +++++++++++++++++++++++++ src/plugins/winrt/qwinrtcameraflashcontrol.h | 76 ++++++++++ src/plugins/winrt/qwinrtcameraservice.cpp | 4 + src/plugins/winrt/winrt.pro | 2 + 6 files changed, 286 insertions(+) create mode 100644 src/plugins/winrt/qwinrtcameraflashcontrol.cpp create mode 100644 src/plugins/winrt/qwinrtcameraflashcontrol.h (limited to 'src') 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 videoDeviceSelector; QPointer imageCaptureControl; QPointer imageEncoderControl; + QPointer cameraFlashControl; QPointer cameraFocusControl; QPointer 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 +#include +#include + +#include +#include +#include + +using namespace Microsoft::WRL; +using namespace ABI::Windows::Media::Devices; + +QT_BEGIN_NAMESPACE + +class QWinRTCameraFlashControlPrivate +{ +public: + ComPtr flashControl; + + QList 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 &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 + +#include + +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 &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 d_ptr; + Q_DECLARE_PRIVATE(QWinRTCameraFlashControl) +}; + +#endif // QWINRTCAMERAFLASHCONTROL_H 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 #include #include +#include #include #include #include @@ -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 \ -- cgit v1.2.3