Android: fix imageCaptured() signal

When capturing two pictures in a row, the second capture would not
trigger the imageCaptured() signal. The reason is that capturing a
picture restarts the preview when done, which in turns clears the
cached last preview frame. The second fetchLastPreviewFrame() would
therefore not do anything.
In this situation, we now retry fetching the frame as soon as a new
one arrives (rather than bailing out).

Task-number: QTBUG-48975
Change-Id: Id5476f37641c04b0edd92bddd40711d5125887f0
Reviewed-by: Christian Stromme <christian.stromme@qt.io>
This commit is contained in:
Yoann Lopes
2016-07-19 14:35:02 +02:00
parent 528588f9f1
commit 4f93cd5a76
2 changed files with 37 additions and 7 deletions

View File

@@ -51,6 +51,7 @@ public class QtCameraListener implements Camera.ShutterCallback,
private int m_cameraId = -1;
private boolean m_notifyNewFrames = false;
private boolean m_notifyWhenFrameAvailable = false;
private byte[][] m_previewBuffers = null;
private byte[] m_lastPreviewBuffer = null;
private Camera.Size m_previewSize = null;
@@ -67,6 +68,11 @@ public class QtCameraListener implements Camera.ShutterCallback,
m_notifyNewFrames = notify;
}
public void notifyWhenFrameAvailable(boolean notify)
{
m_notifyWhenFrameAvailable = notify;
}
public byte[] lastPreviewBuffer()
{
return m_lastPreviewBuffer;
@@ -158,11 +164,17 @@ public class QtCameraListener implements Camera.ShutterCallback,
m_lastPreviewBuffer = data;
if (data != null && m_notifyNewFrames) {
notifyNewPreviewFrame(m_cameraId, data,
m_previewSize.width, m_previewSize.height,
m_previewFormat,
m_previewBytesPerLine);
if (data != null) {
if (m_notifyWhenFrameAvailable) {
m_notifyWhenFrameAvailable = false;
notifyFrameAvailable(m_cameraId);
}
if (m_notifyNewFrames) {
notifyNewPreviewFrame(m_cameraId, data,
m_previewSize.width, m_previewSize.height,
m_previewFormat,
m_previewBytesPerLine);
}
}
}
@@ -189,4 +201,5 @@ public class QtCameraListener implements Camera.ShutterCallback,
private static native void notifyPictureCaptured(int id, byte[] data);
private static native void notifyNewPreviewFrame(int id, byte[] data, int width, int height,
int pixelFormat, int bytesPerLine);
private static native void notifyFrameAvailable(int id);
}

View File

@@ -145,6 +145,16 @@ static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data,
Q_EMIT (*it)->newPreviewFrame(frame);
}
static void notifyFrameAvailable(JNIEnv *, jobject, int id)
{
QReadLocker locker(rwLock);
const auto it = cameras->constFind(id);
if (Q_UNLIKELY(it == cameras->cend()))
return;
(*it)->fetchLastPreviewFrame();
}
class AndroidCameraPrivate : public QObject
{
Q_OBJECT
@@ -1413,6 +1423,9 @@ void AndroidCameraPrivate::stopPreview()
{
QJNIEnvironmentPrivate env;
// cancel any pending new frame notification
m_cameraListener.callMethod<void>("notifyWhenFrameAvailable", "(Z)V", false);
m_camera.callMethod<void>("stopPreview");
exceptionCheckAndClear(env);
@@ -1449,8 +1462,11 @@ void AndroidCameraPrivate::fetchLastPreviewFrame()
QJNIEnvironmentPrivate env;
QJNIObjectPrivate data = m_cameraListener.callObjectMethod("lastPreviewBuffer", "()[B");
if (!data.isValid())
if (!data.isValid()) {
// If there's no buffer received yet, retry when the next one arrives
m_cameraListener.callMethod<void>("notifyWhenFrameAvailable", "(Z)V", true);
return;
}
const int arrayLength = env->GetArrayLength(static_cast<jbyteArray>(data.object()));
if (arrayLength == 0)
@@ -1516,7 +1532,8 @@ bool AndroidCamera::initJNI(JNIEnv *env)
{"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete},
{"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed},
{"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured},
{"notifyNewPreviewFrame", "(I[BIIII)V", (void *)notifyNewPreviewFrame}
{"notifyNewPreviewFrame", "(I[BIIII)V", (void *)notifyNewPreviewFrame},
{"notifyFrameAvailable", "(I)V", (void *)notifyFrameAvailable}
};
if (clazz && env->RegisterNatives(clazz,