Processing thread added to Java camera view.
authorAlexander Smorkalov <alexander.smorkalov@itseez.com>
Fri, 19 Oct 2012 10:40:07 +0000 (14:40 +0400)
committerAndrey Kamaev <andrey.kamaev@itseez.com>
Tue, 23 Oct 2012 16:06:32 +0000 (20:06 +0400)
samples/android/15-puzzle-framework/src/org/opencv/framework/OpenCvJavaCameraView.java

index a3081f2..39f4b2e 100644 (file)
@@ -3,17 +3,20 @@ package org.opencv.framework;
 import java.io.IOException;
 import java.util.List;
 
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.SurfaceTexture;
 import android.hardware.Camera;
 import android.hardware.Camera.PreviewCallback;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.SurfaceHolder;
 
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
-import org.opencv.core.MatOfByte;
+import org.opencv.core.Size;
 import org.opencv.imgproc.Imgproc;
 
 /**
@@ -31,6 +34,10 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements
     private static final String TAG = "OpenCvJavaCameraView";
 
     private Mat mBaseMat;
+    private byte mBuffer[];
+
+    private Thread mThread;
+    private boolean mStopThread;
 
     public static class JavaCameraSizeAccessor implements ListItemAccessor {
 
@@ -45,7 +52,6 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements
             Camera.Size size = (Camera.Size) obj;
             return size.height;
         }
-
     }
 
     private Camera mCamera;
@@ -54,67 +60,179 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements
         super(context, attrs);
     }
 
+    @TargetApi(11)
+    protected boolean initializeCamera(int width, int height) {
+        synchronized (this) {
+            mCamera = null;
+
+            try {
+                mCamera = Camera.open();
+            }
+            catch (Exception e){
+                Log.e(TAG, "Camera is not available (in use or does not exist): " + e.getLocalizedMessage());
+            }
+
+            if(mCamera == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
+                for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) {
+                    try {
+                        mCamera = Camera.open(camIdx);
+                    }
+                    catch (RuntimeException e) {
+                        Log.e(TAG, "Camera #" + camIdx + "failed to open: " + e.getLocalizedMessage());
+                    }
+                }
+            }
+
+            if (mCamera == null)
+                return false;
+
+            mCamera.setPreviewCallbackWithBuffer(this);
+
+            List<android.hardware.Camera.Size> sizes = mCamera.getParameters().getSupportedPreviewSizes();
+            /* Select the size that fits surface considering maximum size allowed */
+            Size frameSize = calculateCameraFrameSize(sizes, new JavaCameraSizeAccessor(), width, height);
+
+            mFrameWidth = (int)frameSize.width;
+            mFrameHeight = (int)frameSize.height;
+
+            /* Now set camera parameters */
+            try {
+                Camera.Parameters params = mCamera.getParameters();
+
+                params.setPreviewFormat(ImageFormat.NV21);
+                params.setPreviewSize((int)frameSize.width, (int)frameSize.height);
+
+                List<String> FocusModes = params.getSupportedFocusModes();
+                if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
+                {
+                    params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
+                }
+
+                mCamera.setParameters(params);
+                params = mCamera.getParameters();
+
+                int size = params.getPreviewSize().width * params.getPreviewSize().height;
+                size  = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
+                mBuffer = new byte[size];
+
+                mCamera.addCallbackBuffer(mBuffer);
+
+                mBaseMat = new Mat(mFrameHeight + (mFrameHeight/2), mFrameWidth, CvType.CV_8UC1);
+
+                AllocateCache();
+
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+                        SurfaceTexture tex = new SurfaceTexture(MAGIC_TEXTURE_ID);
+                        getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+                    mCamera.setPreviewTexture(tex);
+                } else
+                   mCamera.setPreviewDisplay(null);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+
+            /* Finally we are ready to start the preview */
+            mCamera.startPreview();
+        }
 
+        return true;
+    }
 
-    @Override
-    protected void connectCamera(int width, int height) {
-        mCamera = Camera.open(0);
+    protected void releaseCamera() {
+        synchronized (this) {
+            mCamera.stopPreview();
+            mCamera.release();
+            mCamera = null;
+        }
+    }
 
-        List<android.hardware.Camera.Size> sizes = mCamera.getParameters().getSupportedPreviewSizes();
-        /* Select the size that fits surface considering maximum size allowed */
-        FrameSize frameSize = calculateCameraFrameSize(sizes, new JavaCameraSizeAccessor(), width, height);
+    @Override
+    protected boolean connectCamera(int width, int height) {
+
+        /* 1. We need to instantiate camera
+         * 2. We need to start thread which will be getting frames
+         */
+        /* First step - initialize camera connection */
+        Log.d(TAG, "Connecting to camera");
+        if (!initializeCamera(getWidth(), getHeight()))
+            return false;
+
+        /* now we can start update thread */
+        Log.d(TAG, "Starting processing thread");
+        mStopThread = false;
+        mThread = new Thread(new CameraWorker(getWidth(), getHeight()));
+        mThread.start();
+
+        return true;
+    }
 
-        /* Now set camera parameters */
+    protected void disconnectCamera() {
+        /* 1. We need to stop thread which updating the frames
+         * 2. Stop camera and release it
+         */
+        Log.d(TAG, "Disconnecting from camera");
         try {
-            Camera.Parameters params = mCamera.getParameters();
-
-            List<Integer> formats = params.getSupportedPictureFormats();
-
-            params.setPreviewFormat(ImageFormat.NV21);
-            params.setPreviewSize(frameSize.width, frameSize.height);
-
-            mCamera.setPreviewCallback(this);
-            mCamera.setParameters(params);
-            //mCamera.setPreviewTexture(new SurfaceTexture(MAGIC_TEXTURE_ID));
-
-            SurfaceTexture tex = new SurfaceTexture(MAGIC_TEXTURE_ID);
-
-            mCamera.setPreviewTexture(tex);
-
-            mFrameWidth = frameSize.width;
-            mFrameHeight = frameSize.height;
-
-        } catch (IOException e) {
+            mStopThread = true;
+            Log.d(TAG, "Notify thread");
+            synchronized (this) {
+                this.notify();
+                        }
+            Log.d(TAG, "Wating for thread");
+            mThread.join();
+        } catch (InterruptedException e) {
             e.printStackTrace();
+        } finally {
+            mThread =  null;
         }
 
-        mBaseMat = new Mat(mFrameHeight + (mFrameHeight/2), mFrameWidth, CvType.CV_8UC1);
-
-        /* Finally we are ready to start the preview */
-        mCamera.startPreview();
+        /* Now release camera */
+        releaseCamera();
     }
 
     @Override
-    protected void disconnectCamera() {
-
-        mCamera.setPreviewCallback(null);
-        mCamera.stopPreview();
-        mCamera.release();
+    public void onPreviewFrame(byte[] frame, Camera arg1) {
+        Log.i(TAG, "Preview Frame received. Need to create MAT and deliver it to clients");
+        Log.i(TAG, "Frame size  is " + frame.length);
+        synchronized (this)
+        {
+            mBaseMat.put(0, 0, frame);
+            this.notify();
+        }
+        if (mCamera != null)
+            mCamera.addCallbackBuffer(mBuffer);
     }
 
+    private class CameraWorker implements Runnable {
 
+        private Mat mRgba = new Mat();
+        private int mWidth;
+        private int mHeight;
 
-    @Override
-    public void onPreviewFrame(byte[] frame, Camera arg1) {
-        Log.i(TAG, "Preview Frame received. Need to create MAT and deliver it to clients");
-
-        Log.i(TAG, "Frame size  is " + frame.length);
+        CameraWorker(int w, int h) {
+            mWidth = w;
+            mHeight = h;
+        }
 
-        mBaseMat.put(0, 0, frame);
-        Mat frameMat = new Mat();
-        Imgproc.cvtColor(mBaseMat, frameMat, Imgproc.COLOR_YUV2RGBA_NV21, 4);
-        deliverAndDrawFrame(frameMat);
-        frameMat.release();
+        @Override
+        public void run() {
+                do {
+                        synchronized (OpenCvJavaCameraView.this) {
+                        try {
+                                        OpenCvJavaCameraView.this.wait();
+                                } catch (InterruptedException e) {
+                                        // TODO Auto-generated catch block
+                                        e.printStackTrace();
+                                }
+                                }
+
+                        if (!mStopThread) {
+                        Mat frameMat = new Mat();
+                    Imgproc.cvtColor(mBaseMat, frameMat, Imgproc.COLOR_YUV2RGBA_NV21, 4);
+                    deliverAndDrawFrame(frameMat);
+                    frameMat.release();
+                        }
+                } while (!mStopThread);
+                Log.d(TAG, "Finish processing thread");
+        }
     }
-
 }