SampleViewBase.java

Kirill Kornyakov, 2012-06-25 06:02 pm

Download (8.5 kB)

 
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
    // Signal that a camera frame is ready, without blocking the main thread.
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
                // Whenever a camera preview frame is ready, just copy it straight to our mFrame,
66
                // and don't worry about blocking the main UI thread until it is safe.
67
                System.arraycopy(data, 0, mFrame, 0, data.length);
68
                camera.addCallbackBuffer(mBuffer);
69
                
70
                // Signal that a camera frame is ready, without blocking the main thread.
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
                // If this app was paused and restarted, it should wait for camera initialization again.
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
                // selecting optimal camera preview size that is most similar to the screen height.
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
                /* Now allocate the buffer */
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
                /* The buffer where the current frame will be copied */
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
                /* Notify that the preview is about to be started and deliver preview size */
142
                onPreviewStarted(params.getPreviewSize().width, params.getPreviewSize().height);
143
144
                /* Now we can start a preview */
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
    /* The bitmap returned by this method shall be owned by the child and released in onPreviewStopped() */
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
        // Wait until the first camera frame is ready.
189
        try {
190
            while (mThreadRun && !mCameraIsInitialized) {
191
                synchronized (this) {
192
                    wait(100);  // wait 100 milliseconds before trying again.
193
                }
194
            }
195
        } catch (InterruptedException e) {
196
            e.printStackTrace();
197
        }
198
        
199
        // Background processing loop.
200
        // Each iteration of this loop will process the latest camera image and render it to the
201
        // screen. Camera frames will be dropped, if it is not processed fast enough. The user
202
        // interface runs on the "main" thread, so intensive operations here won't delay the user
203
        // interface or cause "Application Not Responding".
204
        while (mThreadRun) {
205
            Bitmap bmp = null;
206
207
            // Process this frame.
208
            synchronized (this) {            
209
                bmp = processFrame(mFrame);
210
            }
211
212
            // Display this frame (on the "main" UI thread).
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
        }//end of background processing loop.
221
222
    }
223
}