From dc21a0a6b5e7891e4b53e016f4549dd069e28eaa Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 17 Feb 2015 01:28:43 +0300 Subject: [PATCH] Android: fix JavaCameraView implementation 1) Fixed deadlock if camera is started and stopped immediately 2) Invalid pattern usage of Object.wait(). Refer to "spurious wakeup": http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait 3) Fixed buffer usage: a) fix eliminates processing of zero NV12 (green in RGB) first frame b) latest ready frame is delivered for processing (not previous) --- .../src/java/android+JavaCameraView.java | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/modules/java/generator/src/java/android+JavaCameraView.java b/modules/java/generator/src/java/android+JavaCameraView.java index 95bdc01f4a..fca29db6eb 100644 --- a/modules/java/generator/src/java/android+JavaCameraView.java +++ b/modules/java/generator/src/java/android+JavaCameraView.java @@ -43,11 +43,13 @@ public class JavaCameraView extends CameraBridgeViewBase implements PreviewCallb public static class JavaCameraSizeAccessor implements ListItemAccessor { + @Override public int getWidth(Object obj) { Camera.Size size = (Camera.Size) obj; return size.width; } + @Override public int getHeight(Object obj) { Camera.Size size = (Camera.Size) obj; return size.height; @@ -228,6 +230,8 @@ public class JavaCameraView extends CameraBridgeViewBase implements PreviewCallb } } + private boolean mCameraFrameReady = false; + @Override protected boolean connectCamera(int width, int height) { @@ -239,6 +243,8 @@ public class JavaCameraView extends CameraBridgeViewBase implements PreviewCallb if (!initializeCamera(width, height)) return false; + mCameraFrameReady = false; + /* now we can start update thread */ Log.d(TAG, "Starting processing thread"); mStopThread = false; @@ -248,6 +254,7 @@ public class JavaCameraView extends CameraBridgeViewBase implements PreviewCallb return true; } + @Override protected void disconnectCamera() { /* 1. We need to stop thread which updating the frames * 2. Stop camera and release it @@ -270,12 +277,16 @@ public class JavaCameraView extends CameraBridgeViewBase implements PreviewCallb /* Now release camera */ releaseCamera(); + + mCameraFrameReady = false; } + @Override public void onPreviewFrame(byte[] frame, Camera arg1) { Log.d(TAG, "Preview Frame received. Frame size: " + frame.length); synchronized (this) { - mFrameChain[1 - mChainIdx].put(0, 0, frame); + mFrameChain[mChainIdx].put(0, 0, frame); + mCameraFrameReady = true; this.notify(); } if (mCamera != null) @@ -283,10 +294,12 @@ public class JavaCameraView extends CameraBridgeViewBase implements PreviewCallb } private class JavaCameraFrame implements CvCameraViewFrame { + @Override public Mat gray() { return mYuvFrameData.submat(0, mHeight, 0, mWidth); } + @Override public Mat rgba() { Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21, 4); return mRgba; @@ -312,21 +325,25 @@ public class JavaCameraView extends CameraBridgeViewBase implements PreviewCallb private class CameraWorker implements Runnable { + @Override public void run() { do { synchronized (JavaCameraView.this) { try { - JavaCameraView.this.wait(); + while (!mCameraFrameReady && !mStopThread) { + JavaCameraView.this.wait(); + } } catch (InterruptedException e) { - // TODO Auto-generated catch block e.printStackTrace(); } + if (mCameraFrameReady) + mChainIdx = 1 - mChainIdx; } - if (!mStopThread) { - if (!mFrameChain[mChainIdx].empty()) - deliverAndDrawFrame(mCameraFrame[mChainIdx]); - mChainIdx = 1 - mChainIdx; + if (!mStopThread && mCameraFrameReady) { + mCameraFrameReady = false; + if (!mFrameChain[1 - mChainIdx].empty()) + deliverAndDrawFrame(mCameraFrame[1 - mChainIdx]); } } while (!mStopThread); Log.d(TAG, "Finish processing thread");