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

https://github.com/nielsgm/opencv · Java · 304 lines · 234 code · 48 blank · 22 comment · 33 complexity · 9711a105c2a7bf017b921719d1d6804e MD5 · raw file

  1. package org.opencv.android;
  2. import java.util.List;
  3. import android.annotation.TargetApi;
  4. import android.content.Context;
  5. import android.graphics.ImageFormat;
  6. import android.graphics.SurfaceTexture;
  7. import android.hardware.Camera;
  8. import android.hardware.Camera.PreviewCallback;
  9. import android.os.Build;
  10. import android.util.AttributeSet;
  11. import android.util.Log;
  12. import android.view.SurfaceHolder;
  13. import org.opencv.core.CvType;
  14. import org.opencv.core.Mat;
  15. import org.opencv.core.Size;
  16. import org.opencv.imgproc.Imgproc;
  17. /**
  18. * This class is an implementation of the Bridge View between OpenCV and Java Camera.
  19. * This class relays on the functionality available in base class and only implements
  20. * required functions:
  21. * connectCamera - opens Java camera and sets the PreviewCallback to be delivered.
  22. * disconnectCamera - closes the camera and stops preview.
  23. * When frame is delivered via callback from Camera - it processed via OpenCV to be
  24. * converted to RGBA32 and then passed to the external callback for modifications if required.
  25. */
  26. public class JavaCameraView extends CameraBridgeViewBase implements PreviewCallback {
  27. private static final int MAGIC_TEXTURE_ID = 10;
  28. private static final String TAG = "JavaCameraView";
  29. private byte mBuffer[];
  30. private Mat[] mFrameChain;
  31. private int mChainIdx = 0;
  32. private Thread mThread;
  33. private boolean mStopThread;
  34. protected Camera mCamera;
  35. protected JavaCameraFrame mCameraFrame;
  36. private SurfaceTexture mSurfaceTexture;
  37. public static class JavaCameraSizeAccessor implements ListItemAccessor {
  38. public int getWidth(Object obj) {
  39. Camera.Size size = (Camera.Size) obj;
  40. return size.width;
  41. }
  42. public int getHeight(Object obj) {
  43. Camera.Size size = (Camera.Size) obj;
  44. return size.height;
  45. }
  46. }
  47. public JavaCameraView(Context context, int cameraId) {
  48. super(context, cameraId);
  49. }
  50. public JavaCameraView(Context context, AttributeSet attrs) {
  51. super(context, attrs);
  52. Log.d(TAG, "Java camera view ctor");
  53. }
  54. @TargetApi(11)
  55. protected boolean initializeCamera(int width, int height) {
  56. Log.d(TAG, "Initialize java camera");
  57. boolean result = true;
  58. synchronized (this) {
  59. mCamera = null;
  60. if (mCameraIndex == -1) {
  61. Log.d(TAG, "Trying to open camera with old open()");
  62. try {
  63. mCamera = Camera.open();
  64. }
  65. catch (Exception e){
  66. Log.e(TAG, "Camera is not available (in use or does not exist): " + e.getLocalizedMessage());
  67. }
  68. if(mCamera == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
  69. boolean connected = false;
  70. for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) {
  71. Log.d(TAG, "Trying to open camera with new open(" + Integer.valueOf(camIdx) + ")");
  72. try {
  73. mCamera = Camera.open(camIdx);
  74. connected = true;
  75. } catch (RuntimeException e) {
  76. Log.e(TAG, "Camera #" + camIdx + "failed to open: " + e.getLocalizedMessage());
  77. }
  78. if (connected) break;
  79. }
  80. }
  81. } else {
  82. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
  83. Log.d(TAG, "Trying to open camera with new open(" + Integer.valueOf(mCameraIndex) + ")");
  84. try {
  85. mCamera = Camera.open(mCameraIndex);
  86. } catch (RuntimeException e) {
  87. Log.e(TAG, "Camera #" + mCameraIndex + "failed to open: " + e.getLocalizedMessage());
  88. }
  89. }
  90. }
  91. if (mCamera == null)
  92. return false;
  93. /* Now set camera parameters */
  94. try {
  95. Camera.Parameters params = mCamera.getParameters();
  96. Log.d(TAG, "getSupportedPreviewSizes()");
  97. List<android.hardware.Camera.Size> sizes = params.getSupportedPreviewSizes();
  98. if (sizes != null) {
  99. /* Select the size that fits surface considering maximum size allowed */
  100. Size frameSize = calculateCameraFrameSize(sizes, new JavaCameraSizeAccessor(), width, height);
  101. params.setPreviewFormat(ImageFormat.NV21);
  102. Log.d(TAG, "Set preview size to " + Integer.valueOf((int)frameSize.width) + "x" + Integer.valueOf((int)frameSize.height));
  103. params.setPreviewSize((int)frameSize.width, (int)frameSize.height);
  104. List<String> FocusModes = params.getSupportedFocusModes();
  105. if (FocusModes != null && FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
  106. {
  107. params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
  108. }
  109. mCamera.setParameters(params);
  110. params = mCamera.getParameters();
  111. mFrameWidth = params.getPreviewSize().width;
  112. mFrameHeight = params.getPreviewSize().height;
  113. if (mFpsMeter != null) {
  114. mFpsMeter.setResolution(mFrameWidth, mFrameHeight);
  115. }
  116. int size = mFrameWidth * mFrameHeight;
  117. size = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
  118. mBuffer = new byte[size];
  119. mCamera.addCallbackBuffer(mBuffer);
  120. mCamera.setPreviewCallbackWithBuffer(this);
  121. mFrameChain = new Mat[2];
  122. mFrameChain[0] = new Mat(mFrameHeight + (mFrameHeight/2), mFrameWidth, CvType.CV_8UC1);
  123. mFrameChain[1] = new Mat(mFrameHeight + (mFrameHeight/2), mFrameWidth, CvType.CV_8UC1);
  124. AllocateCache();
  125. mCameraFrame = new JavaCameraFrame(mFrameChain[mChainIdx], mFrameWidth, mFrameHeight);
  126. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
  127. mSurfaceTexture = new SurfaceTexture(MAGIC_TEXTURE_ID);
  128. getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  129. mCamera.setPreviewTexture(mSurfaceTexture);
  130. } else
  131. mCamera.setPreviewDisplay(null);
  132. /* Finally we are ready to start the preview */
  133. Log.d(TAG, "startPreview");
  134. mCamera.startPreview();
  135. }
  136. else
  137. result = false;
  138. } catch (Exception e) {
  139. result = false;
  140. e.printStackTrace();
  141. }
  142. }
  143. return result;
  144. }
  145. protected void releaseCamera() {
  146. synchronized (this) {
  147. if (mCamera != null) {
  148. mCamera.stopPreview();
  149. mCamera.release();
  150. }
  151. mCamera = null;
  152. if (mFrameChain != null) {
  153. mFrameChain[0].release();
  154. mFrameChain[1].release();
  155. }
  156. if (mCameraFrame != null)
  157. mCameraFrame.release();
  158. }
  159. }
  160. @Override
  161. protected boolean connectCamera(int width, int height) {
  162. /* 1. We need to instantiate camera
  163. * 2. We need to start thread which will be getting frames
  164. */
  165. /* First step - initialize camera connection */
  166. Log.d(TAG, "Connecting to camera");
  167. if (!initializeCamera(width, height))
  168. return false;
  169. /* now we can start update thread */
  170. Log.d(TAG, "Starting processing thread");
  171. mStopThread = false;
  172. mThread = new Thread(new CameraWorker());
  173. mThread.start();
  174. return true;
  175. }
  176. protected void disconnectCamera() {
  177. /* 1. We need to stop thread which updating the frames
  178. * 2. Stop camera and release it
  179. */
  180. Log.d(TAG, "Disconnecting from camera");
  181. try {
  182. mStopThread = true;
  183. Log.d(TAG, "Notify thread");
  184. synchronized (this) {
  185. this.notify();
  186. }
  187. Log.d(TAG, "Wating for thread");
  188. if (mThread != null)
  189. mThread.join();
  190. } catch (InterruptedException e) {
  191. e.printStackTrace();
  192. } finally {
  193. mThread = null;
  194. }
  195. /* Now release camera */
  196. releaseCamera();
  197. }
  198. @TargetApi(Build.VERSION_CODES.FROYO)
  199. public void onPreviewFrame(byte[] frame, Camera arg1) {
  200. Log.i(TAG, "Preview Frame received. Need to create MAT and deliver it to clients");
  201. Log.i(TAG, "Frame size is " + frame.length);
  202. synchronized (this)
  203. {
  204. mFrameChain[1 - mChainIdx].put(0, 0, frame);
  205. this.notify();
  206. }
  207. if (mCamera != null)
  208. mCamera.addCallbackBuffer(mBuffer);
  209. }
  210. private class JavaCameraFrame implements CvCameraViewFrame
  211. {
  212. public Mat gray() {
  213. return mYuvFrameData.submat(0, mHeight, 0, mWidth);
  214. }
  215. public Mat rgba() {
  216. Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2BGR_NV12, 4);
  217. return mRgba;
  218. }
  219. public JavaCameraFrame(Mat Yuv420sp, int width, int height) {
  220. super();
  221. mWidth = width;
  222. mHeight = height;
  223. mYuvFrameData = Yuv420sp;
  224. mRgba = new Mat();
  225. }
  226. public void release() {
  227. mRgba.release();
  228. }
  229. private JavaCameraFrame(CvCameraViewFrame obj) {
  230. }
  231. private Mat mYuvFrameData;
  232. private Mat mRgba;
  233. private int mWidth;
  234. private int mHeight;
  235. };
  236. private class CameraWorker implements Runnable {
  237. public void run() {
  238. do {
  239. synchronized (JavaCameraView.this) {
  240. try {
  241. JavaCameraView.this.wait();
  242. } catch (InterruptedException e) {
  243. // TODO Auto-generated catch block
  244. e.printStackTrace();
  245. }
  246. }
  247. if (!mStopThread) {
  248. if (!mFrameChain[mChainIdx].empty())
  249. deliverAndDrawFrame(mCameraFrame);
  250. mChainIdx = 1 - mChainIdx;
  251. }
  252. } while (!mStopThread);
  253. Log.d(TAG, "Finish processing thread");
  254. }
  255. }
  256. }