From 68ab3d5be63849afaecb525e932f817ceba8843a Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 19 Oct 2012 14:40:07 +0400 Subject: [PATCH] Processing thread added to Java camera view. --- .../org/opencv/framework/OpenCvJavaCameraView.java | 214 ++++++++++++++++----- 1 file changed, 166 insertions(+), 48 deletions(-) diff --git a/samples/android/15-puzzle-framework/src/org/opencv/framework/OpenCvJavaCameraView.java b/samples/android/15-puzzle-framework/src/org/opencv/framework/OpenCvJavaCameraView.java index a3081f2..39f4b2e 100644 --- a/samples/android/15-puzzle-framework/src/org/opencv/framework/OpenCvJavaCameraView.java +++ b/samples/android/15-puzzle-framework/src/org/opencv/framework/OpenCvJavaCameraView.java @@ -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 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 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 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 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"); + } } - } -- 2.7.4