summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java72
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.cpp20
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.h1
-rw-r--r--src/plugins/android/src/wrappers/jcamera.cpp35
-rw-r--r--src/plugins/android/src/wrappers/jcamera.h6
5 files changed, 91 insertions, 43 deletions
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
index 3d891196f..4aa07b713 100644
--- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCamera.java
@@ -42,8 +42,11 @@
package org.qtproject.qt5.android.multimedia;
import android.hardware.Camera;
+import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.util.Log;
+import java.lang.Math;
+import java.util.concurrent.locks.ReentrantLock;
public class QtCamera implements Camera.ShutterCallback,
Camera.PictureCallback,
@@ -52,6 +55,11 @@ public class QtCamera implements Camera.ShutterCallback,
{
private int m_cameraId = -1;
private Camera m_camera = null;
+ private byte[] m_cameraPreviewFirstBuffer = null;
+ private byte[] m_cameraPreviewSecondBuffer = null;
+ private int m_actualPreviewBuffer = 0;
+ private final ReentrantLock m_buffersLock = new ReentrantLock();
+ private boolean m_isReleased = false;
private static final String TAG = "Qt Camera";
@@ -97,6 +105,7 @@ public class QtCamera implements Camera.ShutterCallback,
public void release()
{
+ m_isReleased = true;
m_camera.release();
}
@@ -134,6 +143,22 @@ public class QtCamera implements Camera.ShutterCallback,
public void startPreview()
{
+ Camera.Size previewSize = m_camera.getParameters().getPreviewSize();
+ double bytesPerPixel = ImageFormat.getBitsPerPixel(m_camera.getParameters().getPreviewFormat()) / 8.0;
+ int bufferSizeNeeded = (int)Math.ceil(bytesPerPixel*previewSize.width*previewSize.height);
+
+ //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.setPreviewCallback(null);
+ m_buffersLock.lock();
+ if (m_cameraPreviewFirstBuffer == null || m_cameraPreviewFirstBuffer.length < bufferSizeNeeded)
+ m_cameraPreviewFirstBuffer = new byte[bufferSizeNeeded];
+ if (m_cameraPreviewSecondBuffer == null || m_cameraPreviewSecondBuffer.length < bufferSizeNeeded)
+ m_cameraPreviewSecondBuffer = new byte[bufferSizeNeeded];
+ addCallbackBuffer();
+ m_buffersLock.unlock();
+ m_camera.setPreviewCallbackWithBuffer(this);
+
m_camera.startPreview();
}
@@ -152,11 +177,6 @@ public class QtCamera implements Camera.ShutterCallback,
m_camera.cancelAutoFocus();
}
- public void requestPreviewFrame()
- {
- m_camera.setOneShotPreviewCallback(this);
- }
-
public void takePicture()
{
try {
@@ -166,6 +186,37 @@ public class QtCamera implements Camera.ShutterCallback,
}
}
+ public byte[] lockAndFetchPreviewBuffer()
+ {
+ //This method should always be followed by unlockPreviewBuffer()
+ //This method is not just a getter. It also marks last preview as already seen one.
+ //We should reset actualBuffer flag here to make sure we will not use old preview with future captures
+ byte[] result = null;
+ m_buffersLock.lock();
+ if (m_actualPreviewBuffer == 1)
+ result = m_cameraPreviewFirstBuffer;
+ else if (m_actualPreviewBuffer == 2)
+ result = m_cameraPreviewSecondBuffer;
+ m_actualPreviewBuffer = 0;
+ return result;
+ }
+
+ public void unlockPreviewBuffer()
+ {
+ if (m_buffersLock.isHeldByCurrentThread())
+ m_buffersLock.unlock();
+ }
+
+ private void addCallbackBuffer()
+ {
+ if (m_isReleased)
+ return;
+
+ m_camera.addCallbackBuffer((m_actualPreviewBuffer == 1)
+ ? m_cameraPreviewSecondBuffer
+ : m_cameraPreviewFirstBuffer);
+ }
+
@Override
public void onShutter()
{
@@ -181,7 +232,15 @@ public class QtCamera implements Camera.ShutterCallback,
@Override
public void onPreviewFrame(byte[] data, Camera camera)
{
- notifyPreviewFrame(m_cameraId, data);
+ m_buffersLock.lock();
+ if (data == m_cameraPreviewFirstBuffer)
+ m_actualPreviewBuffer = 1;
+ else if (data == m_cameraPreviewSecondBuffer)
+ m_actualPreviewBuffer = 2;
+ else
+ m_actualPreviewBuffer = 0;
+ addCallbackBuffer();
+ m_buffersLock.unlock();
}
@Override
@@ -193,5 +252,4 @@ public class QtCamera implements Camera.ShutterCallback,
private static native void notifyAutoFocusComplete(int id, boolean success);
private static native void notifyPictureExposed(int id);
private static native void notifyPictureCaptured(int id, byte[] data);
- private static native void notifyPreviewFrame(int id, byte[] data);
}
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
index 5ff19d1c1..55065cb46 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp
@@ -183,7 +183,6 @@ bool QAndroidCameraSession::open()
if (m_camera) {
connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed()));
connect(m_camera, SIGNAL(pictureCaptured(QByteArray)), this, SLOT(onCameraPictureCaptured(QByteArray)));
- connect(m_camera, SIGNAL(previewFrameAvailable(QByteArray)), this, SLOT(onCameraPreviewFrameAvailable(QByteArray)));
m_nativeOrientation = m_camera->getNativeOrientation();
@@ -484,7 +483,6 @@ int QAndroidCameraSession::capture(const QString &fileName)
// adjust picture rotation depending on the device orientation
m_camera->setRotation(currentCameraRotation());
- m_camera->requestPreviewFrame();
m_camera->takePicture();
} else {
//: Drive mode is the camera's shutter mode, for example single shot, continuos exposure, etc.
@@ -509,6 +507,13 @@ void QAndroidCameraSession::onCameraPictureExposed()
return;
emit imageExposed(m_currentImageCaptureId);
+ QByteArray lastFrame = m_camera->fetchLastPreviewFrame();
+ if (lastFrame.size()) {
+ QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage,
+ m_currentImageCaptureId,
+ lastFrame,
+ m_camera->getRotation());
+ }
}
void QAndroidCameraSession::onCameraPictureCaptured(const QByteArray &data)
@@ -571,17 +576,6 @@ void QAndroidCameraSession::processCapturedImage(int id,
}
}
-void QAndroidCameraSession::onCameraPreviewFrameAvailable(const QByteArray &data)
-{
- if (m_captureCanceled || m_readyForCapture)
- return;
-
- QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage,
- m_currentImageCaptureId,
- data,
- m_camera->getRotation());
-}
-
void QAndroidCameraSession::processPreviewImage(int id, const QByteArray &data, int rotation)
{
QSize frameSize = m_camera->previewSize();
diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
index 17ea4171f..61d8c1a17 100644
--- a/src/plugins/android/src/mediacapture/qandroidcamerasession.h
+++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h
@@ -114,7 +114,6 @@ private Q_SLOTS:
void onCameraPictureExposed();
void onCameraPictureCaptured(const QByteArray &data);
- void onCameraPreviewFrameAvailable(const QByteArray &data);
private:
bool open();
diff --git a/src/plugins/android/src/wrappers/jcamera.cpp b/src/plugins/android/src/wrappers/jcamera.cpp
index e69cb554d..5712ae356 100644
--- a/src/plugins/android/src/wrappers/jcamera.cpp
+++ b/src/plugins/android/src/wrappers/jcamera.cpp
@@ -102,18 +102,6 @@ static void notifyPictureCaptured(JNIEnv *env, jobject, int id, jbyteArray data)
}
}
-static void notifyPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data)
-{
- JCamera *obj = g_objectMap.value(id, 0);
- if (obj) {
- QByteArray bytes;
- int arrayLength = env->GetArrayLength(data);
- bytes.resize(arrayLength);
- env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
- Q_EMIT obj->previewFrameAvailable(bytes);
- }
-}
-
JCamera::JCamera(int cameraId, jobject cam)
: QObject()
, QJNIObjectPrivate(cam)
@@ -667,14 +655,26 @@ void JCamera::setJpegQuality(int quality)
applyParameters();
}
-void JCamera::requestPreviewFrame()
+void JCamera::takePicture()
{
- callMethod<void>("requestPreviewFrame");
+ callMethod<void>("takePicture");
}
-void JCamera::takePicture()
+QByteArray JCamera::fetchLastPreviewFrame()
{
- callMethod<void>("takePicture");
+ QJNIEnvironmentPrivate env;
+ QJNIObjectPrivate dataObj = callObjectMethod("lockAndFetchPreviewBuffer", "()[B");
+ if (!dataObj.object()) {
+ callMethod<void>("unlockPreviewBuffer");
+ return QByteArray();
+ }
+ jbyteArray data = static_cast<jbyteArray>(dataObj.object());
+ QByteArray bytes;
+ int arrayLength = env->GetArrayLength(data);
+ bytes.resize(arrayLength);
+ env->GetByteArrayRegion(data, 0, arrayLength, (jbyte*)bytes.data());
+ callMethod<void>("unlockPreviewBuffer");
+ return bytes;
}
void JCamera::startPreview()
@@ -720,8 +720,7 @@ QStringList JCamera::callStringListMethod(const char *methodName)
static JNINativeMethod methods[] = {
{"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete},
{"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed},
- {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured},
- {"notifyPreviewFrame", "(I[B)V", (void *)notifyPreviewFrame}
+ {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured}
};
bool JCamera::initJNI(JNIEnv *env)
diff --git a/src/plugins/android/src/wrappers/jcamera.h b/src/plugins/android/src/wrappers/jcamera.h
index 7c47ec7a2..6bba98402 100644
--- a/src/plugins/android/src/wrappers/jcamera.h
+++ b/src/plugins/android/src/wrappers/jcamera.h
@@ -147,10 +147,10 @@ public:
void startPreview();
void stopPreview();
- void requestPreviewFrame();
-
void takePicture();
+ QByteArray fetchLastPreviewFrame();
+
static bool initJNI(JNIEnv *env);
Q_SIGNALS:
@@ -161,8 +161,6 @@ Q_SIGNALS:
void whiteBalanceChanged();
- void previewFrameAvailable(const QByteArray &data);
-
void pictureExposed();
void pictureCaptured(const QByteArray &data);