Android: fix JavaCameraView implementation
authorAlexander Alekhin <alexander.alekhin@itseez.com>
Mon, 16 Feb 2015 22:28:43 +0000 (01:28 +0300)
committerAlexander Alekhin <alexander.alekhin@itseez.com>
Tue, 24 Feb 2015 15:52:54 +0000 (18:52 +0300)
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)

modules/java/generator/src/java/android+JavaCameraView.java

index c29ba2b..09df4f8 100644 (file)
@@ -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");