diff options
author | Yoann Lopes <yoann.lopes@theqtcompany.com> | 2015-08-24 14:31:24 +0200 |
---|---|---|
committer | Yoann Lopes <yoann.lopes@theqtcompany.com> | 2015-08-24 14:36:13 +0200 |
commit | a2244c9b7aa11e386c3331cbbc36336fb8fea3b9 (patch) | |
tree | a77ac99aa38c40e98aa483795e3cb8061f404203 /src/plugins/android/src | |
parent | 31fce88b3fcdbb4d4b2b9a889d24e25c3a5c9507 (diff) | |
parent | 008d20e0ece4c6dac148915b998a0005657d73a1 (diff) |
Merge remote-tracking branch 'origin/5.5' into 5.6
Conflicts:
src/imports/multimedia/qdeclarativeaudio.cpp
Change-Id: I57c6252b084e4ed796f6f308b2e0c717d0f59b13
Diffstat (limited to 'src/plugins/android/src')
5 files changed, 85 insertions, 75 deletions
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index 4a64e1b1a..179bcdf96 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -206,9 +206,10 @@ bool QAndroidCameraSession::open() if (m_camera) { connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed())); - connect(m_camera, SIGNAL(previewFetched(QByteArray)), this, SLOT(onCameraPreviewFetched(QByteArray))); - connect(m_camera, SIGNAL(frameFetched(QByteArray)), - this, SLOT(onCameraFrameFetched(QByteArray)), + connect(m_camera, SIGNAL(lastPreviewFrameFetched(QByteArray,int,int)), + this, SLOT(onLastPreviewFrameFetched(QByteArray,int,int))); + connect(m_camera, SIGNAL(newPreviewFrame(QByteArray,int,int)), + this, SLOT(onNewPreviewFrame(QByteArray,int,int)), Qt::DirectConnection); connect(m_camera, SIGNAL(pictureCaptured(QByteArray)), this, SLOT(onCameraPictureCaptured(QByteArray))); connect(m_camera, SIGNAL(previewStarted()), this, SLOT(onCameraPreviewStarted())); @@ -221,7 +222,7 @@ bool QAndroidCameraSession::open() if (m_camera->getPreviewFormat() != AndroidCamera::NV21) m_camera->setPreviewFormat(AndroidCamera::NV21); - m_camera->fetchEachFrame(m_videoProbes.count()); + m_camera->notifyNewFrames(m_videoProbes.count()); emit opened(); } else { @@ -410,7 +411,7 @@ void QAndroidCameraSession::addProbe(QAndroidMediaVideoProbeControl *probe) if (probe) m_videoProbes << probe; if (m_camera) - m_camera->fetchEachFrame(m_videoProbes.count()); + m_camera->notifyNewFrames(m_videoProbes.count()); m_videoProbesMutex.unlock(); } @@ -419,7 +420,7 @@ void QAndroidCameraSession::removeProbe(QAndroidMediaVideoProbeControl *probe) m_videoProbesMutex.lock(); m_videoProbes.remove(probe); if (m_camera) - m_camera->fetchEachFrame(m_videoProbes.count()); + m_camera->notifyNewFrames(m_videoProbes.count()); m_videoProbesMutex.unlock(); } @@ -562,25 +563,54 @@ void QAndroidCameraSession::onCameraPictureExposed() m_camera->fetchLastPreviewFrame(); } -void QAndroidCameraSession::onCameraPreviewFetched(const QByteArray &preview) +void QAndroidCameraSession::onLastPreviewFrameFetched(const QByteArray &preview, int width, int height) { if (preview.size()) { QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage, m_currentImageCaptureId, preview, + width, + height, m_camera->getRotation()); } } -void QAndroidCameraSession::onCameraFrameFetched(const QByteArray &frame) +void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data, int width, int height, int rotation) +{ + emit imageCaptured(id, prepareImageFromPreviewData(data, width, height, rotation)); +} + +QImage QAndroidCameraSession::prepareImageFromPreviewData(const QByteArray &data, int width, int height, int rotation) +{ + QImage result(width, height, QImage::Format_ARGB32); + qt_convert_NV21_to_ARGB32((const uchar *)data.constData(), + (quint32 *)result.bits(), + width, + height); + + QTransform transform; + + // Preview display of front-facing cameras is flipped horizontally, but the frame data + // we get here is not. Flip it ourselves if the camera is front-facing to match what the user + // sees on the viewfinder. + if (m_camera->getFacing() == AndroidCamera::CameraFacingFront) + transform.scale(-1, 1); + + transform.rotate(rotation); + + result = result.transformed(transform); + + return result; +} + +void QAndroidCameraSession::onNewPreviewFrame(const QByteArray &frame, int width, int height) { m_videoProbesMutex.lock(); if (frame.size() && m_videoProbes.count()) { - const QSize frameSize = m_camera->previewSize(); // Bytes per line should be only for the first plane. For NV21, the Y plane has 8 bits // per sample, so bpl == width - QVideoFrame videoFrame(new DataVideoBuffer(frame, frameSize.width()), - frameSize, + QVideoFrame videoFrame(new DataVideoBuffer(frame, width), + QSize(width, height), QVideoFrame::Format_NV21); foreach (QAndroidMediaVideoProbeControl *probe, m_videoProbes) probe->newFrameProbed(videoFrame); @@ -666,35 +696,6 @@ void QAndroidCameraSession::processCapturedImage(int id, } } -void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data, int rotation) -{ - emit imageCaptured(id, prepareImageFromPreviewData(data, rotation)); -} - -QImage QAndroidCameraSession::prepareImageFromPreviewData(const QByteArray &data, int rotation) -{ - QSize frameSize = m_camera->previewSize(); - QImage result(frameSize, QImage::Format_ARGB32); - qt_convert_NV21_to_ARGB32((const uchar *)data.constData(), - (quint32 *)result.bits(), - frameSize.width(), - frameSize.height()); - - QTransform transform; - - // Preview display of front-facing cameras is flipped horizontally, but the frame data - // we get here is not. Flip it ourselves if the camera is front-facing to match what the user - // sees on the viewfinder. - if (m_camera->getFacing() == AndroidCamera::CameraFacingFront) - transform.scale(-1, 1); - - transform.rotate(rotation); - - result = result.transformed(transform); - - return result; -} - void QAndroidCameraSession::onVideoOutputReady(bool ready) { if (ready && m_state == QCamera::ActiveState) diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h index 879fb3ca3..a56721bcd 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.h +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h @@ -113,9 +113,9 @@ private Q_SLOTS: void onApplicationStateChanged(Qt::ApplicationState state); void onCameraPictureExposed(); - void onCameraPreviewFetched(const QByteArray &preview); - void onCameraFrameFetched(const QByteArray &frame); void onCameraPictureCaptured(const QByteArray &data); + void onLastPreviewFrameFetched(const QByteArray &preview, int width, int height); + void onNewPreviewFrame(const QByteArray &frame, int width, int height); void onCameraPreviewStarted(); void onCameraPreviewStopped(); @@ -129,8 +129,8 @@ private: void stopPreview(); void applyImageSettings(); - void processPreviewImage(int id, const QByteArray &data, int rotation); - QImage prepareImageFromPreviewData(const QByteArray &data, int rotation); + void processPreviewImage(int id, const QByteArray &data, int width, int height, int rotation); + QImage prepareImageFromPreviewData(const QByteArray &data, int width, int height, int rotation); void processCapturedImage(int id, const QByteArray &data, const QSize &resolution, diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp index aaad8fd8a..f2ea1b9d7 100644 --- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp @@ -233,9 +233,14 @@ void QAndroidCaptureSession::start() m_notifyTimer.start(); updateDuration(); - if (m_cameraSession) + if (m_cameraSession) { m_cameraSession->setReadyForCapture(false); + // Preview frame callback is cleared when setting up the camera with the media recorder. + // We need to reset it. + m_cameraSession->camera()->setupPreviewFrameCallback(); + } + m_state = QMediaRecorder::RecordingState; emit stateChanged(m_state); } diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp index 7496e9cdc..a4acbd8f9 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp +++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp @@ -114,7 +114,7 @@ static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data) } } -static void notifyFrameFetched(JNIEnv *env, jobject, int id, jbyteArray data) +static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data, int width, int height) { QMutexLocker locker(&g_cameraMapMutex); AndroidCamera *obj = g_cameraMap->value(id, 0); @@ -123,7 +123,7 @@ static void notifyFrameFetched(JNIEnv *env, jobject, int id, jbyteArray data) QByteArray bytes(arrayLength, Qt::Uninitialized); env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data()); - Q_EMIT obj->frameFetched(bytes); + Q_EMIT obj->newPreviewFrame(bytes, width, height); } } @@ -204,7 +204,8 @@ public: Q_INVOKABLE void takePicture(); - Q_INVOKABLE void fetchEachFrame(bool fetch); + Q_INVOKABLE void setupPreviewFrameCallback(); + Q_INVOKABLE void notifyNewFrames(bool notify); Q_INVOKABLE void fetchLastPreviewFrame(); Q_INVOKABLE void applyParameters(); @@ -229,7 +230,7 @@ Q_SIGNALS: void whiteBalanceChanged(); - void previewFetched(const QByteArray &preview); + void lastPreviewFrameFetched(const QByteArray &preview, int width, int height); }; AndroidCamera::AndroidCamera(AndroidCameraPrivate *d, QThread *worker) @@ -247,7 +248,7 @@ AndroidCamera::AndroidCamera(AndroidCameraPrivate *d, QThread *worker) connect(d, &AndroidCameraPrivate::previewStopped, this, &AndroidCamera::previewStopped); connect(d, &AndroidCameraPrivate::autoFocusStarted, this, &AndroidCamera::autoFocusStarted); connect(d, &AndroidCameraPrivate::whiteBalanceChanged, this, &AndroidCamera::whiteBalanceChanged); - connect(d, &AndroidCameraPrivate::previewFetched, this, &AndroidCamera::previewFetched); + connect(d, &AndroidCameraPrivate::lastPreviewFrameFetched, this, &AndroidCamera::lastPreviewFrameFetched); } AndroidCamera::~AndroidCamera() @@ -633,10 +634,16 @@ void AndroidCamera::takePicture() QMetaObject::invokeMethod(d, "takePicture", Qt::BlockingQueuedConnection); } -void AndroidCamera::fetchEachFrame(bool fetch) +void AndroidCamera::setupPreviewFrameCallback() { Q_D(AndroidCamera); - QMetaObject::invokeMethod(d, "fetchEachFrame", Q_ARG(bool, fetch)); + QMetaObject::invokeMethod(d, "setupPreviewFrameCallback"); +} + +void AndroidCamera::notifyNewFrames(bool notify) +{ + Q_D(AndroidCamera); + QMetaObject::invokeMethod(d, "notifyNewFrames", Q_ARG(bool, notify)); } void AndroidCamera::fetchLastPreviewFrame() @@ -1307,17 +1314,7 @@ void AndroidCameraPrivate::setJpegQuality(int quality) void AndroidCameraPrivate::startPreview() { - //We need to clear preview buffers queue here, but there is no method to do it - //Though just resetting preview callback do the trick - m_camera.callMethod<void>("setPreviewCallbackWithBuffer", - "(Landroid/hardware/Camera$PreviewCallback;)V", - jobject(0)); - m_cameraListener.callMethod<void>("preparePreviewBuffer", "(Landroid/hardware/Camera;)V", m_camera.object()); - QJNIObjectPrivate buffer = m_cameraListener.callObjectMethod<jbyteArray>("callbackBuffer"); - m_camera.callMethod<void>("addCallbackBuffer", "([B)V", buffer.object()); - m_camera.callMethod<void>("setPreviewCallbackWithBuffer", - "(Landroid/hardware/Camera$PreviewCallback;)V", - m_cameraListener.object()); + setupPreviewFrameCallback(); m_camera.callMethod<void>("startPreview"); emit previewStarted(); } @@ -1338,28 +1335,34 @@ void AndroidCameraPrivate::takePicture() m_cameraListener.object()); } -void AndroidCameraPrivate::fetchEachFrame(bool fetch) +void AndroidCameraPrivate::setupPreviewFrameCallback() { - m_cameraListener.callMethod<void>("fetchEachFrame", "(Z)V", fetch); + m_cameraListener.callMethod<void>("setupPreviewCallback", "(Landroid/hardware/Camera;)V", m_camera.object()); +} + +void AndroidCameraPrivate::notifyNewFrames(bool notify) +{ + m_cameraListener.callMethod<void>("notifyNewFrames", "(Z)V", notify); } void AndroidCameraPrivate::fetchLastPreviewFrame() { QJNIEnvironmentPrivate env; - QJNIObjectPrivate data = m_cameraListener.callObjectMethod("lockAndFetchPreviewBuffer", "()[B"); - if (!data.isValid()) { - m_cameraListener.callMethod<void>("unlockPreviewBuffer"); + QJNIObjectPrivate data = m_cameraListener.callObjectMethod("lastPreviewBuffer", "()[B"); + + if (!data.isValid()) return; - } + const int arrayLength = env->GetArrayLength(static_cast<jbyteArray>(data.object())); QByteArray bytes(arrayLength, Qt::Uninitialized); env->GetByteArrayRegion(static_cast<jbyteArray>(data.object()), 0, arrayLength, reinterpret_cast<jbyte *>(bytes.data())); - m_cameraListener.callMethod<void>("unlockPreviewBuffer"); - emit previewFetched(bytes); + emit lastPreviewFrameFetched(bytes, + m_cameraListener.callMethod<jint>("previewWidth"), + m_cameraListener.callMethod<jint>("previewHeight")); } void AndroidCameraPrivate::applyParameters() @@ -1404,7 +1407,7 @@ bool AndroidCamera::initJNI(JNIEnv *env) {"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete}, {"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed}, {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured}, - {"notifyFrameFetched", "(I[B)V", (void *)notifyFrameFetched} + {"notifyNewPreviewFrame", "(I[BII)V", (void *)notifyNewPreviewFrame} }; if (clazz && env->RegisterNatives(clazz, diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.h b/src/plugins/android/src/wrappers/jni/androidcamera.h index a14b77c7f..7a8ae8b23 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.h +++ b/src/plugins/android/src/wrappers/jni/androidcamera.h @@ -155,7 +155,8 @@ public: void takePicture(); - void fetchEachFrame(bool fetch); + void setupPreviewFrameCallback(); + void notifyNewFrames(bool notify); void fetchLastPreviewFrame(); QJNIObjectPrivate getCameraObject(); @@ -176,8 +177,8 @@ Q_SIGNALS: void pictureExposed(); void pictureCaptured(const QByteArray &data); - void previewFetched(const QByteArray &preview); - void frameFetched(const QByteArray &frame); + void lastPreviewFrameFetched(const QByteArray &preview, int width, int height); + void newPreviewFrame(const QByteArray &frame, int width, int height); private: AndroidCamera(AndroidCameraPrivate *d, QThread *worker); |