1 | package org.opencv.samples.tutorial3;
|
2 |
|
3 | import java.io.IOException;
|
4 | import java.util.List;
|
5 | import android.content.Context;
|
6 | import android.graphics.Bitmap;
|
7 | import android.graphics.Canvas;
|
8 | import android.graphics.ImageFormat;
|
9 | import android.graphics.SurfaceTexture;
|
10 | import android.hardware.Camera;
|
11 | import android.hardware.Camera.PreviewCallback;
|
12 | import android.os.Build;
|
13 | import android.util.Log;
|
14 | import android.view.SurfaceHolder;
|
15 | import android.view.SurfaceView;
|
16 |
|
17 | public abstract class SampleViewBase extends SurfaceView implements SurfaceHolder.Callback, Runnable {
|
18 | private static final String TAG = "Sample::SurfaceView";
|
19 |
|
20 | private Camera mCamera;
|
21 | private SurfaceHolder mHolder;
|
22 | private int mFrameWidth;
|
23 | private int mFrameHeight;
|
24 | private byte[] mFrame;
|
25 | private boolean mThreadRun;
|
26 | private byte[] mBuffer;
|
27 |
|
28 |
|
29 | private boolean mCameraIsInitialized = false;
|
30 |
|
31 |
|
32 | public SampleViewBase(Context context) {
|
33 | super(context);
|
34 | mHolder = getHolder();
|
35 | mHolder.addCallback(this);
|
36 | Log.i(TAG, "Instantiated new " + this.getClass());
|
37 | }
|
38 |
|
39 | public int getFrameWidth() {
|
40 | return mFrameWidth;
|
41 | }
|
42 |
|
43 | public int getFrameHeight() {
|
44 | return mFrameHeight;
|
45 | }
|
46 |
|
47 | public void setPreview() throws IOException {
|
48 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
49 | mCamera.setPreviewTexture( new SurfaceTexture(10) );
|
50 | else
|
51 | mCamera.setPreviewDisplay(null);
|
52 | }
|
53 |
|
54 | public boolean openCamera() {
|
55 | Log.i(TAG, "openCamera");
|
56 | releaseCamera();
|
57 | mCamera = Camera.open();
|
58 | if(mCamera == null) {
|
59 | Log.e(TAG, "Can't open camera!");
|
60 | return false;
|
61 | }
|
62 |
|
63 | mCamera.setPreviewCallbackWithBuffer(new PreviewCallback() {
|
64 | public void onPreviewFrame(byte[] data, Camera camera) {
|
65 |
|
66 |
|
67 | System.arraycopy(data, 0, mFrame, 0, data.length);
|
68 | camera.addCallbackBuffer(mBuffer);
|
69 |
|
70 |
|
71 | mCameraIsInitialized = true;
|
72 | }
|
73 | });
|
74 | return true;
|
75 | }
|
76 |
|
77 | public void releaseCamera() {
|
78 | Log.i(TAG, "releaseCamera");
|
79 | mThreadRun = false;
|
80 | synchronized (this) {
|
81 | if (mCamera != null) {
|
82 | mCamera.stopPreview();
|
83 | mCamera.setPreviewCallback(null);
|
84 | mCamera.release();
|
85 | mCamera = null;
|
86 |
|
87 |
|
88 | mCameraIsInitialized = false;
|
89 | }
|
90 | }
|
91 | onPreviewStopped();
|
92 | }
|
93 |
|
94 | public void setupCamera(int width, int height) {
|
95 | Log.i(TAG, "setupCamera");
|
96 | synchronized (this) {
|
97 | if (mCamera != null) {
|
98 | Camera.Parameters params = mCamera.getParameters();
|
99 | List<Camera.Size> sizes = params.getSupportedPreviewSizes();
|
100 | mFrameWidth = width;
|
101 | mFrameHeight = height;
|
102 |
|
103 |
|
104 | {
|
105 | int minDiff = Integer.MAX_VALUE;
|
106 | for (Camera.Size size : sizes) {
|
107 | if (Math.abs(size.height - height) < minDiff) {
|
108 | mFrameWidth = size.width;
|
109 | mFrameHeight = size.height;
|
110 | minDiff = Math.abs(size.height - height);
|
111 | }
|
112 | }
|
113 | }
|
114 |
|
115 | params.setPreviewSize(getFrameWidth(), getFrameHeight());
|
116 |
|
117 | List<String> FocusModes = params.getSupportedFocusModes();
|
118 | if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
|
119 | {
|
120 | params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
|
121 | }
|
122 |
|
123 | mCamera.setParameters(params);
|
124 |
|
125 |
|
126 | params = mCamera.getParameters();
|
127 | Log.i(TAG, "Camera Preview Size: " + params.getPreviewSize().width + "x" + params.getPreviewSize().height);
|
128 | int size = params.getPreviewSize().width * params.getPreviewSize().height;
|
129 | size = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
|
130 | mBuffer = new byte[size];
|
131 |
|
132 | mFrame = new byte [size];
|
133 | mCamera.addCallbackBuffer(mBuffer);
|
134 |
|
135 | try {
|
136 | setPreview();
|
137 | } catch (IOException e) {
|
138 | Log.e(TAG, "mCamera.setPreviewDisplay/setPreviewTexture fails: " + e);
|
139 | }
|
140 |
|
141 |
|
142 | onPreviewStarted(params.getPreviewSize().width, params.getPreviewSize().height);
|
143 |
|
144 |
|
145 | mCamera.startPreview();
|
146 | }
|
147 | }
|
148 | }
|
149 |
|
150 | public void surfaceChanged(SurfaceHolder _holder, int format, int width, int height) {
|
151 | Log.i(TAG, "surfaceChanged");
|
152 | setupCamera(width, height);
|
153 | }
|
154 |
|
155 | public void surfaceCreated(SurfaceHolder holder) {
|
156 | Log.i(TAG, "surfaceCreated");
|
157 | (new Thread(this)).start();
|
158 | }
|
159 |
|
160 | public void surfaceDestroyed(SurfaceHolder holder) {
|
161 | Log.i(TAG, "surfaceDestroyed");
|
162 | releaseCamera();
|
163 | }
|
164 |
|
165 |
|
166 |
|
167 | protected abstract Bitmap processFrame(byte[] data);
|
168 |
|
169 | |
170 | * This method is called when the preview process is being started. It is called before the first frame delivered and processFrame is called
|
171 | * It is called with the width and height parameters of the preview process. It can be used to prepare the data needed during the frame processing.
|
172 | * @param previewWidth - the width of the preview frames that will be delivered via processFrame
|
173 | * @param previewHeight - the height of the preview frames that will be delivered via processFrame
|
174 | */
|
175 | protected abstract void onPreviewStarted(int previewWidtd, int previewHeight);
|
176 |
|
177 | |
178 | * This method is called when preview is stopped. When this method is called the preview stopped and all the processing of frames already completed.
|
179 | * If the Bitmap object returned via processFrame is cached - it is a good time to recycle it.
|
180 | * Any other resources used during the preview can be released.
|
181 | */
|
182 | protected abstract void onPreviewStopped();
|
183 |
|
184 | public void run() {
|
185 | mThreadRun = true;
|
186 | Log.i(TAG, "Starting processing thread");
|
187 |
|
188 |
|
189 | try {
|
190 | while (mThreadRun && !mCameraIsInitialized) {
|
191 | synchronized (this) {
|
192 | wait(100);
|
193 | }
|
194 | }
|
195 | } catch (InterruptedException e) {
|
196 | e.printStackTrace();
|
197 | }
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 | while (mThreadRun) {
|
205 | Bitmap bmp = null;
|
206 |
|
207 |
|
208 | synchronized (this) {
|
209 | bmp = processFrame(mFrame);
|
210 | }
|
211 |
|
212 |
|
213 | if (bmp != null) {
|
214 | Canvas canvas = mHolder.lockCanvas();
|
215 | if (canvas != null) {
|
216 | canvas.drawBitmap(bmp, (canvas.getWidth() - getFrameWidth()) / 2, (canvas.getHeight() - getFrameHeight()) / 2, null);
|
217 | mHolder.unlockCanvasAndPost(canvas);
|
218 | }
|
219 | }
|
220 | }
|
221 |
|
222 | }
|
223 | }
|