content: package org.opencv.android;
  
  import org.opencv.core.Mat;
  import org.opencv.core.Size;
  import org.opencv.highgui.Highgui;
  import org.opencv.highgui.VideoCapture;
  
  import android.content.Context;
  import android.util.AttributeSet;
  import android.util.Log;
  import android.view.ViewGroup.LayoutParams;
  
  /**
   * This class is an implementation of a bridge between SurfaceView and native OpenCV camera.
   * Due to the big amount of work done, by the base class this child is only responsible
   * for creating camera, destroying camera and delivering frames while camera is enabled
   */
  public class NativeCameraView extends CameraBridgeViewBase {
  
      public static final String TAG = "NativeCameraView";
      private boolean mStopThread;
      private Thread mThread;
  
      protected VideoCapture mCamera;
      protected NativeCameraFrame mFrame;
  
      public NativeCameraView(Context context, int cameraId) {
          super(context, cameraId);
      }
  
      public NativeCameraView(Context context, AttributeSet attrs) {
          super(context, attrs);
      }
  
      @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 */
          if (!initializeCamera(width, height))
              return false;
  
          /* now we can start update thread */
          mThread = new Thread(new CameraWorker());
          mThread.start();
  
          return true;
      }
  
      @Override
      protected void disconnectCamera() {
          /* 1. We need to stop thread which updating the frames
           * 2. Stop camera and release it
           */
          if (mThread != null) {
              try {
                  mStopThread = true;
                  mThread.join();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              } finally {
                  mThread =  null;
                  mStopThread = false;
              }
          }
  
          /* Now release camera */
          releaseCamera();
      }
  
      public static class OpenCvSizeAccessor implements ListItemAccessor {
  
          public int getWidth(Object obj) {
              Size size  = (Size)obj;
              return (int)size.width;
          }
  
          public int getHeight(Object obj) {
              Size size  = (Size)obj;
              return (int)size.height;
          }
  
      }
  
      private boolean initializeCamera(int width, int height) {
          synchronized (this) {
  
              if (mCameraIndex == -1)
                  mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID);
              else
                  mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID + mCameraIndex);
  
              if (mCamera == null)
                  return false;
  
              if (mCamera.isOpened() == false)
                  return false;
  
              mFrame = new NativeCameraFrame(mCamera);
  
              java.util.List<Size> sizes = mCamera.getSupportedPreviewSizes();
  
              /* Select the size that fits surface considering maximum size allowed */
              Size frameSize = calculateCameraFrameSize(sizes, new OpenCvSizeAccessor(), width, height);
  
              mFrameWidth = (int)frameSize.width;
              mFrameHeight = (int)frameSize.height;
  
              if ((getLayoutParams().width == LayoutParams.MATCH_PARENT) && (getLayoutParams().height == LayoutParams.MATCH_PARENT))
                  mScale = Math.min(((float)height)/mFrameHeight, ((float)width)/mFrameWidth);
              else
                  mScale = 0;
  
              if (mFpsMeter != null) {
                  mFpsMeter.setResolution(mFrameWidth, mFrameHeight);
              }
  
              AllocateCache();
  
              mCamera.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, frameSize.width);
              mCamera.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, frameSize.height);
          }
  
          Log.i(TAG, "Selected camera frame size = (" + mFrameWidth + ", " + mFrameHeight + ")");
  
          return true;
      }
  
      private void releaseCamera() {
          synchronized (this) {
              if (mFrame != null) mFrame.release();
              if (mCamera != null) mCamera.release();
          }
      }
  
      private static class NativeCameraFrame implements CvCameraViewFrame {
  
          @Override
          public Mat rgba() {
              mCapture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
              return mRgba;
          }
  
          @Override
          public Mat gray() {
              mCapture.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);
              return mGray;
          }
  
          public NativeCameraFrame(VideoCapture capture) {
              mCapture = capture;
              mGray = new Mat();
              mRgba = new Mat();
          }
  
          public void release() {
              if (mGray != null) mGray.release();
              if (mRgba != null) mRgba.release();
          }
  
          private VideoCapture mCapture;
          private Mat mRgba;
          private Mat mGray;
      };
  
      private class CameraWorker implements Runnable {
  
          public void run() {
              do {
                  if (!mCamera.grab()) {
                      Log.e(TAG, "Camera frame grab failed");
                      break;
                  }
  
                  deliverAndDrawFrame(mFrame);
              } while (!mStopThread);
          }
      }
  
  }
  