summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2015-05-11 10:01:29 +0200
committerLiang Qi <liang.qi@theqtcompany.com>2015-05-11 10:01:29 +0200
commit66613b4f9cada951b1f25c5d0f77bee88824c710 (patch)
tree3735e47019e9bde30a5197c5f7d6a39757a00f68 /src/plugins
parent176d52bb28b425f697ad8df001ba2c7c52fda766 (diff)
parent0761f2d53f6e6d2b482326442100693542142a52 (diff)
Merge remote-tracking branch 'origin/5.5' into dev
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcapturesession.cpp28
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcapturesession.h2
-rw-r--r--src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h1
-rw-r--r--src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm9
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.h3
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.mm38
-rw-r--r--src/plugins/avfoundation/camera/avfmediarecordercontrol.h5
-rw-r--r--src/plugins/avfoundation/camera/avfmediarecordercontrol.mm62
-rw-r--r--src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp23
9 files changed, 101 insertions, 70 deletions
diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
index fcc104584..af8033026 100644
--- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
@@ -151,23 +151,19 @@ void QAndroidCaptureSession::setState(QMediaRecorder::State state)
stop();
break;
case QMediaRecorder::RecordingState:
- if (!start())
- return;
+ start();
break;
case QMediaRecorder::PausedState:
// Not supported by Android API
qWarning("QMediaRecorder::PausedState is not supported on Android");
- return;
+ break;
}
-
- m_state = state;
- emit stateChanged(m_state);
}
-bool QAndroidCaptureSession::start()
+void QAndroidCaptureSession::start()
{
if (m_state == QMediaRecorder::RecordingState || m_status != QMediaRecorder::LoadedStatus)
- return false;
+ return;
setStatus(QMediaRecorder::StartingStatus);
@@ -225,13 +221,13 @@ bool QAndroidCaptureSession::start()
if (!m_mediaRecorder->prepare()) {
emit error(QMediaRecorder::FormatError, QLatin1String("Unable to prepare the media recorder."));
restartViewfinder();
- return false;
+ return;
}
if (!m_mediaRecorder->start()) {
emit error(QMediaRecorder::FormatError, QLatin1String("Unable to start the media recorder."));
restartViewfinder();
- return false;
+ return;
}
m_elapsedTime.start();
@@ -241,22 +237,21 @@ bool QAndroidCaptureSession::start()
if (m_cameraSession)
m_cameraSession->setReadyForCapture(false);
- return true;
+ m_state = QMediaRecorder::RecordingState;
+ emit stateChanged(m_state);
}
void QAndroidCaptureSession::stop(bool error)
{
- if (m_state == QMediaRecorder::StoppedState)
+ if (m_state == QMediaRecorder::StoppedState || m_mediaRecorder == 0)
return;
setStatus(QMediaRecorder::FinalizingStatus);
m_mediaRecorder->stop();
-
m_notifyTimer.stop();
updateDuration();
m_elapsedTime.invalidate();
-
m_mediaRecorder->release();
delete m_mediaRecorder;
m_mediaRecorder = 0;
@@ -279,6 +274,9 @@ void QAndroidCaptureSession::stop(bool error)
m_actualOutputLocation = m_usedOutputLocation;
emit actualLocationChanged(m_actualOutputLocation);
}
+
+ m_state = QMediaRecorder::StoppedState;
+ emit stateChanged(m_state);
}
void QAndroidCaptureSession::setStatus(QMediaRecorder::Status status)
@@ -541,8 +539,6 @@ void QAndroidCaptureSession::onError(int what, int extra)
Q_UNUSED(what)
Q_UNUSED(extra)
stop(true);
- m_state = QMediaRecorder::StoppedState;
- emit stateChanged(m_state);
emit error(QMediaRecorder::ResourceError, QLatin1String("Unknown error."));
}
diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.h b/src/plugins/android/src/mediacapture/qandroidcapturesession.h
index 81e570426..90af39fd7 100644
--- a/src/plugins/android/src/mediacapture/qandroidcapturesession.h
+++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.h
@@ -130,7 +130,7 @@ private:
CaptureProfile getProfile(int id);
- bool start();
+ void start();
void stop(bool error = false);
void setStatus(QMediaRecorder::Status status);
diff --git a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h
index b4704160e..8ad89bcc2 100644
--- a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h
+++ b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h
@@ -69,6 +69,7 @@ private:
QString m_activeInput;
bool m_dirty;
+ QString m_defaultDevice;
QStringList m_devices;
QMap<QString, QString> m_deviceDescriptions;
};
diff --git a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm
index ebfce1edc..d0d0c8209 100644
--- a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm
+++ b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm
@@ -52,8 +52,11 @@ AVFAudioInputSelectorControl::AVFAudioInputSelectorControl(AVFCameraService *ser
QString::fromUtf8([[device localizedName] UTF8String]));
}
- if (m_devices.size() > 0)
- m_activeInput = m_devices.first();
+ AVCaptureDevice *defaultDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
+ if (defaultDevice) {
+ m_defaultDevice = QString::fromUtf8([defaultDevice.uniqueID UTF8String]);
+ m_activeInput = m_defaultDevice;
+ }
}
AVFAudioInputSelectorControl::~AVFAudioInputSelectorControl()
@@ -72,7 +75,7 @@ QString AVFAudioInputSelectorControl::inputDescription(const QString &name) cons
QString AVFAudioInputSelectorControl::defaultInput() const
{
- return m_devices.size() > 0 ? m_devices.first() : QString();
+ return m_defaultDevice;
}
QString AVFAudioInputSelectorControl::activeInput() const
diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h
index 4772351e6..7b25a99c3 100644
--- a/src/plugins/avfoundation/camera/avfcamerasession.h
+++ b/src/plugins/avfoundation/camera/avfcamerasession.h
@@ -99,7 +99,7 @@ Q_SIGNALS:
private:
static void updateCameraDevices();
- void attachInputDevices();
+ void attachVideoInputDevice();
void applyImageEncoderSettings();
void applyViewfinderSettings();
@@ -114,7 +114,6 @@ private:
AVCaptureSession *m_captureSession;
AVCaptureDeviceInput *m_videoInput;
- AVCaptureDeviceInput *m_audioInput;
AVFCameraSessionObserver *m_observer;
QSet<AVFMediaVideoProbeControl *> m_videoProbes;
diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm
index 48fe428d8..6e4803f30 100644
--- a/src/plugins/avfoundation/camera/avfcamerasession.mm
+++ b/src/plugins/avfoundation/camera/avfcamerasession.mm
@@ -143,7 +143,6 @@ AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent)
, m_state(QCamera::UnloadedState)
, m_active(false)
, m_videoInput(nil)
- , m_audioInput(nil)
, m_defaultCodec(0)
{
m_captureSession = [[AVCaptureSession alloc] init];
@@ -160,11 +159,6 @@ AVFCameraSession::~AVFCameraSession()
[m_videoInput release];
}
- if (m_audioInput) {
- [m_captureSession removeInput:m_audioInput];
- [m_audioInput release];
- }
-
[m_observer release];
[m_captureSession release];
}
@@ -283,10 +277,9 @@ void AVFCameraSession::setState(QCamera::State newState)
QCamera::State oldState = m_state;
m_state = newState;
- //attach audio and video inputs during Unloaded->Loaded transition
- if (oldState == QCamera::UnloadedState) {
- attachInputDevices();
- }
+ //attach video input during Unloaded->Loaded transition
+ if (oldState == QCamera::UnloadedState)
+ attachVideoInputDevice();
if (m_state == QCamera::ActiveState) {
Q_EMIT readyToConfigureConnections();
@@ -332,7 +325,7 @@ void AVFCameraSession::processSessionStopped()
}
}
-void AVFCameraSession::attachInputDevices()
+void AVFCameraSession::attachVideoInputDevice()
{
//Attach video input device:
if (m_service->videoDeviceControl()->isDirty()) {
@@ -360,29 +353,6 @@ void AVFCameraSession::attachInputDevices()
}
}
}
-
- //Attach audio input device:
- if (m_service->audioInputSelectorControl()->isDirty()) {
- if (m_audioInput) {
- [m_captureSession removeInput:m_audioInput];
- [m_audioInput release];
- m_audioInput = 0;
- }
-
- AVCaptureDevice *audioDevice = m_service->audioInputSelectorControl()->createCaptureDevice();
-
- NSError *error = nil;
- m_audioInput = [AVCaptureDeviceInput
- deviceInputWithDevice:audioDevice
- error:&error];
-
- if (!m_audioInput) {
- qWarning() << "Failed to create audio device input";
- } else {
- [m_audioInput retain];
- [m_captureSession addInput:m_audioInput];
- }
- }
}
void AVFCameraSession::applyImageEncoderSettings()
diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol.h b/src/plugins/avfoundation/camera/avfmediarecordercontrol.h
index a303c0b5f..4ea25ae2b 100644
--- a/src/plugins/avfoundation/camera/avfmediarecordercontrol.h
+++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol.h
@@ -46,6 +46,7 @@ QT_BEGIN_NAMESPACE
class AVFCameraSession;
class AVFCameraControl;
+class AVFAudioInputSelectorControl;
class AVFCameraService;
class AVFMediaRecorderControl : public QMediaRecorderControl
@@ -78,11 +79,12 @@ public Q_SLOTS:
void handleRecordingFailed(const QString &message);
private Q_SLOTS:
- void reconnectMovieOutput();
+ void setupSessionForCapture();
void updateStatus();
private:
AVFCameraControl *m_cameraControl;
+ AVFAudioInputSelectorControl *m_audioInputControl;
AVFCameraSession *m_session;
bool m_connected;
@@ -96,6 +98,7 @@ private:
bool m_muted;
qreal m_volume;
+ AVCaptureDeviceInput *m_audioInput;
AVCaptureMovieFileOutput *m_movieOutput;
AVFMediaRecorderDelegate *m_recorderDelagate;
AVFStorageLocation m_storageLocation;
diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm
index 3bc24fcc7..412dab76c 100644
--- a/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm
+++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm
@@ -36,6 +36,7 @@
#include "avfcamerasession.h"
#include "avfcameraservice.h"
#include "avfcameracontrol.h"
+#include "avfaudioinputselectorcontrol.h"
#include <QtCore/qurl.h>
#include <QtCore/qfileinfo.h>
@@ -114,6 +115,7 @@ QT_USE_NAMESPACE
AVFMediaRecorderControl::AVFMediaRecorderControl(AVFCameraService *service, QObject *parent)
: QMediaRecorderControl(parent)
, m_cameraControl(service->cameraControl())
+ , m_audioInputControl(service->audioInputSelectorControl())
, m_session(service->session())
, m_connected(false)
, m_state(QMediaRecorder::StoppedState)
@@ -122,21 +124,29 @@ AVFMediaRecorderControl::AVFMediaRecorderControl(AVFCameraService *service, QObj
, m_recordingFinished(false)
, m_muted(false)
, m_volume(1.0)
+ , m_audioInput(nil)
{
m_movieOutput = [[AVCaptureMovieFileOutput alloc] init];
m_recorderDelagate = [[AVFMediaRecorderDelegate alloc] initWithRecorder:this];
connect(m_cameraControl, SIGNAL(stateChanged(QCamera::State)), SLOT(updateStatus()));
connect(m_cameraControl, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateStatus()));
- connect(m_cameraControl, SIGNAL(captureModeChanged(QCamera::CaptureModes)), SLOT(reconnectMovieOutput()));
-
- reconnectMovieOutput();
+ connect(m_cameraControl, SIGNAL(captureModeChanged(QCamera::CaptureModes)), SLOT(setupSessionForCapture()));
+ connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(setupSessionForCapture()));
+ connect(m_session, SIGNAL(stateChanged(QCamera::State)), SLOT(setupSessionForCapture()));
}
AVFMediaRecorderControl::~AVFMediaRecorderControl()
{
- if (m_movieOutput)
+ if (m_movieOutput) {
[m_session->captureSession() removeOutput:m_movieOutput];
+ [m_movieOutput release];
+ }
+
+ if (m_audioInput) {
+ [m_session->captureSession() removeInput:m_audioInput];
+ [m_audioInput release];
+ }
[m_recorderDelagate release];
}
@@ -307,13 +317,39 @@ void AVFMediaRecorderControl::handleRecordingFailed(const QString &message)
Q_EMIT error(QMediaRecorder::ResourceError, message);
}
-void AVFMediaRecorderControl::reconnectMovieOutput()
+void AVFMediaRecorderControl::setupSessionForCapture()
{
//adding movie output causes high CPU usage even when while recording is not active,
- //connect it only while video capture mode is enabled
+ //connect it only while video capture mode is enabled.
+ // Similarly, connect the Audio input only in that mode, since it's only necessary
+ // when recording anyway. Adding an Audio input will trigger the microphone permission
+ // request on iOS, but it shoudn't do so until we actually try to record.
AVCaptureSession *captureSession = m_session->captureSession();
- if (!m_connected && m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo)) {
+ if (!m_connected
+ && m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo)
+ && m_session->state() != QCamera::UnloadedState) {
+
+ // Add audio input
+ // Allow recording even if something wrong happens with the audio input initialization
+ AVCaptureDevice *audioDevice = m_audioInputControl->createCaptureDevice();
+ if (!audioDevice) {
+ qWarning("No audio input device available");
+ } else {
+ NSError *error = nil;
+ m_audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
+
+ if (!m_audioInput) {
+ qWarning() << "Failed to create audio device input";
+ } else if (![captureSession canAddInput:m_audioInput]) {
+ qWarning() << "Could not connect the audio input";
+ m_audioInput = 0;
+ } else {
+ [m_audioInput retain];
+ [captureSession addInput:m_audioInput];
+ }
+ }
+
if ([captureSession canAddOutput:m_movieOutput]) {
[captureSession addOutput:m_movieOutput];
m_connected = true;
@@ -321,8 +357,18 @@ void AVFMediaRecorderControl::reconnectMovieOutput()
Q_EMIT error(QMediaRecorder::ResourceError, tr("Could not connect the video recorder"));
qWarning() << "Could not connect the video recorder";
}
- } else if (m_connected && !m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo)) {
+ } else if (m_connected
+ && (!m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo)
+ || m_session->state() != QCamera::ActiveState)) {
+
[captureSession removeOutput:m_movieOutput];
+
+ if (m_audioInput) {
+ [captureSession removeInput:m_audioInput];
+ [m_audioInput release];
+ m_audioInput = nil;
+ }
+
m_connected = false;
}
diff --git a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp
index 74afabaf3..bcae8a201 100644
--- a/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp
+++ b/src/plugins/winrt/qwinrtcameravideorenderercontrol.cpp
@@ -132,11 +132,14 @@ private:
ComPtr<ID3D11VideoProcessorOutputView> m_outputView;
};
+#define CAMERA_SAMPLE_QUEUE_SIZE 5
class QWinRTCameraVideoRendererControlPrivate
{
public:
QScopedPointer<D3DVideoBlitter> blitter;
- QVector<ComPtr<IMF2DBuffer>> buffers;
+ ComPtr<IMF2DBuffer> buffers[CAMERA_SAMPLE_QUEUE_SIZE];
+ QAtomicInteger<quint16> writeIndex;
+ QAtomicInteger<quint16> readIndex;
};
QWinRTCameraVideoRendererControl::QWinRTCameraVideoRendererControl(const QSize &size, QObject *parent)
@@ -153,13 +156,17 @@ bool QWinRTCameraVideoRendererControl::render(ID3D11Texture2D *target)
{
Q_D(QWinRTCameraVideoRendererControl);
- if (d->buffers.isEmpty()) {
+ const quint16 readIndex = d->readIndex;
+ if (readIndex == d->writeIndex) {
emit bufferRequested();
return false;
}
HRESULT hr;
- ComPtr<IMF2DBuffer> buffer = d->buffers.takeFirst();
+ ComPtr<IMF2DBuffer> buffer = d->buffers[readIndex];
+ Q_ASSERT(buffer);
+ d->buffers[readIndex].Reset();
+ d->readIndex = (readIndex + 1) % CAMERA_SAMPLE_QUEUE_SIZE;
ComPtr<ID3D11Texture2D> sourceTexture;
ComPtr<IMFDXGIBuffer> dxgiBuffer;
@@ -186,11 +193,17 @@ void QWinRTCameraVideoRendererControl::queueBuffer(IMF2DBuffer *buffer)
{
Q_D(QWinRTCameraVideoRendererControl);
Q_ASSERT(buffer);
- d->buffers.append(buffer);
+ const quint16 writeIndex = (d->writeIndex + 1) % CAMERA_SAMPLE_QUEUE_SIZE;
+ if (d->readIndex == writeIndex) // Drop new sample if queue is full
+ return;
+ d->buffers[d->writeIndex] = buffer;
+ d->writeIndex = writeIndex;
}
void QWinRTCameraVideoRendererControl::discardBuffers()
{
Q_D(QWinRTCameraVideoRendererControl);
- d->buffers.clear();
+ d->writeIndex = d->readIndex = 0;
+ for (ComPtr<IMF2DBuffer> &buffer : d->buffers)
+ buffer.Reset();
}