This source file includes following definitions.
- processFrameBuf
- startPreview
- stopPreview
- surfaceChanged
- surfaceCreated
- surfaceDestroyed
- finalize
- finalize
- initializeCamera
- getPreviewSize
- getPreviewFormat
- getImageHeight
- getImageWidth
- getBitsPerPixel
- stopCamera
- pausePreview
- resumePreview
- setParameters
- getOptimalPreviewSize
- getOptimalPreviewFormat
- processFrame
- saveImageToFile
- decodeYUV420SP
- setPreviewCallbackWithBuffer
- addCallbackBuffer
- getCamAddCallbackBuffer
- getCamSetPreviewCallbackWithBuffer
- onPreviewFrame
- onLooperPrepared
- stopPreview
package com.gpac.Osmo4;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.List;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.LinearLayout;
public class Preview {
private static final String TAG = "Preview";
private Camera mCamera = null;
private Size mPreviewSize = null;
private int nBuffers = 0;
private int mBufferSize = 0;
private int mPreviewFormat = 0;
private PreviewHandler mPreviewHandler = null;
private boolean takePicture = false;
private boolean mPreviewing = false;
private boolean isPortrait = false;
private int width = 0;
private int height = 0;
private int bitsPerPixel = 0;
public static Activity context = null;
private boolean previewRequested = false;
private boolean previewStarted = false;
private CameraPreview camPreview = null;
private native void processFrameBuf(byte[] data);
Preview() {
mCamera = Camera.open();
if (mCamera == null) {
Log.e(TAG, "Camera failed to open");
return;
}
setParameters(mCamera.getParameters());
mCamera.release();
mCamera = null;
}
private class CameraPreview implements SurfaceHolder.Callback {
private SurfaceHolder holder = null;
private SurfaceView mCamSV;
private boolean hasCallback = false;
private ProgressDialog cameraOpening;
public CameraPreview(final Activity context) {
Log.v(TAG, "CameraPreview: Constructor...");
cameraOpening = new ProgressDialog(context);
cameraOpening.setCancelable(false);
cameraOpening.setIndeterminate(true);
cameraOpening.setMessage("Opening camera");
cameraOpening.setTitle("Osmo4 camera");
context.runOnUiThread(new Runnable() {
@Override
public void run() {
cameraOpening.show();
}
});
mCamSV = (SurfaceView)context.findViewById(R.id.surface_camera);
holder = mCamSV.getHolder();
holder.addCallback(CameraPreview.this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
hasCallback = true;
context.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i(TAG, "CameraPreview: Set visible...");
mCamSV.setVisibility(View.VISIBLE);
Log.i(TAG, "CameraPreview: Set visible done");
}
});
Log.v(TAG, "CameraPreview: Constructor done");
}
public void startPreview()
{
Log.v(TAG, "CameraPreview: Start preview...");
mCamera.startPreview();
context.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i(TAG, "CameraPreview: Dismiss");
cameraOpening.dismiss();
}
});
mPreviewHandler = new PreviewHandler("CameraPreviewHandler");
mPreviewing = true;
Log.v(TAG, "CameraPreview: Start preview done");
}
public void stopPreview()
{
if ( hasCallback )
{
Log.v(TAG, "CameraPreview: Remove callback");
holder.removeCallback(CameraPreview.this);
context.runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i(TAG, "CameraPreview: Set gone...");
mCamSV.setVisibility(View.GONE);
Log.i(TAG, "CameraPreview: Set gone done");
}
});
hasCallback = false;
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.v(TAG, "CameraPreview: Surface changed "+width+"x"+height+" ...");
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
Log.v(TAG, "CameraPreview: Surface created...");
mCamera.setPreviewDisplay(holder);
if ( previewRequested ) {
startPreview();
previewRequested = false;
}
else
previewStarted = true;
Log.v(TAG, "CameraPreview: Surface created done");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
@Override
public void finalize()
{
stopPreview();
camPreview = null;
}
}
@Override
protected void finalize() {
stopCamera();
}
public boolean initializeCamera(boolean isPortrait) {
this.isPortrait = isPortrait;
if (mCamera == null) {
Log.i(TAG, "Open camera...");
mCamera = Camera.open();
if (mCamera == null) {
Log.w(TAG, "Camera failed to open");
return false;
}
}
pausePreview();
mCamera.setParameters(setParameters(mCamera.getParameters()));
width = mPreviewSize.width;
height = mPreviewSize.height;
if (mPreviewSize == null || mPreviewFormat == 0) {
Log.e(TAG, "Preview size or format error");
return false;
}
PixelFormat pixelinfo = new PixelFormat();
PixelFormat.getPixelFormatInfo(mPreviewFormat, pixelinfo);
bitsPerPixel = pixelinfo.bitsPerPixel;
mBufferSize = mPreviewSize.width * mPreviewSize.height * pixelinfo.bitsPerPixel / 8;
Log.d(TAG, "Pixelsize = " + pixelinfo.bitsPerPixel + " Buffersize = " + mBufferSize);
nBuffers = 1;
context.runOnUiThread(new Runnable() {
@Override
public void run() {
camPreview = new CameraPreview(context);
}
});
Log.d(TAG, "Camera preview started");
return true;
}
public Size getPreviewSize() {
return mPreviewSize;
}
public int getPreviewFormat() {
return mPreviewFormat;
}
public int getImageHeight() {
Size sz = getPreviewSize();
if (sz == null)
return -1;
return sz.height;
}
public int getImageWidth() {
Size sz = getPreviewSize();
if (sz == null)
return -1;
return sz.width;
}
public int getBitsPerPixel() {
return bitsPerPixel;
}
public void stopCamera() {
Log.v(TAG, "stopCamera()");
if ( mPreviewing )
pausePreview();
if (mCamera != null) {
camPreview.stopPreview();
camPreview = null;
mCamera.release();
mCamera = null;
previewRequested = false;
previewStarted = false;
Log.v(TAG, "Camera released");
}
}
public void pausePreview() {
Log.v(TAG, "pausePreview()");
if ( mPreviewing ) {
if ( mPreviewHandler != null )
mPreviewHandler.stopPreview();
mPreviewHandler = null;
mCamera.stopPreview();
mPreviewing = false;
Log.v(TAG, "Camera preview stopped");
}
}
public void resumePreview() {
Log.v(TAG, "resumePreview()");
if ( previewStarted ) {
camPreview.startPreview();
previewStarted = false;
}
else
previewRequested = true;
}
protected Camera.Parameters setParameters(Camera.Parameters parameters) throws IllegalArgumentException {
if (parameters == null)
throw new IllegalArgumentException("parameters must not be null");
mPreviewSize = parameters.getPreviewSize();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
Log.d(TAG, "PreviewSize: " + mPreviewSize.width + 'x' + mPreviewSize.height);
mPreviewFormat = PixelFormat.YCbCr_420_SP;
if (mPreviewFormat == 0) {
Log.e(TAG, "Cannot set mPreviewFormat");
} else {
Log.d(TAG, "Previewformat: " + mPreviewFormat);
parameters.setPreviewFormat(mPreviewFormat);
}
Log.d(TAG, "PreviewFrameRate: " + parameters.getPreviewFrameRate());
parameters.setPreviewFrameRate(parameters.getPreviewFrameRate());
parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO );
return parameters;
}
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
protected int getOptimalPreviewFormat(List<Integer> formats) {
int optFormat = 0;
for (Integer format : formats) {
int intFormat = format.intValue();
Log.d(TAG, "supported image format: " + intFormat);
if (intFormat == PixelFormat.YCbCr_420_SP) {
optFormat = intFormat;
}
}
return optFormat;
}
protected void processFrame(byte[] data) {
if (takePicture) {
int[] rgbBuf = decodeYUV420SP(data, width, height);
saveImageToFile(rgbBuf, width, height);
takePicture = false;
}
processFrameBuf(data);
}
public void saveImageToFile(int[] rgbBuffer, int width, int height) {
Bitmap bm = Bitmap.createBitmap(rgbBuffer, width, height, Bitmap.Config.RGB_565);
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
File file = new File(path, "image.jpg");
try {
try {
fOut = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.flush();
} catch (IOException e1) {
Log.e(TAG, "io error file output stream while writing", e1);
e1.printStackTrace();
} finally {
if (fOut != null)
fOut.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public int[] decodeYUV420SP(byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
int rgb[] = new int[width * height];
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & (yuv420sp[yp])) - 16;
if (y < 0)
y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0)
r = 0;
else if (r > 262143)
r = 262143;
if (g < 0)
g = 0;
else if (g > 262143)
g = 262143;
if (b < 0)
b = 0;
else if (b > 262143)
b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
return rgb;
}
private void setPreviewCallbackWithBuffer(Camera.PreviewCallback cb) {
try {
if (bufferWorks) {
if (cb != null) {
for (int i = 0; i < nBuffers; i++) {
camAddCbBuffer.invoke(mCamera, new byte[mBufferSize]);
}
}
camSetPreview.invoke(mCamera, cb);
} else if (cb != null) {
mCamera.setOneShotPreviewCallback(cb);
}
} catch (Exception e) {
Log.e(TAG, "setPreviewCallbackWithBuffer failed:" + e, e);
}
}
private int fps_max_count = 100;
private int fps_count = 1;
private long fps_last = -42;
private void addCallbackBuffer(byte[] buffer) {
if (--fps_count == 0) {
long now = System.currentTimeMillis();
if (fps_last != -42) {
float fps = fps_max_count * 1000.f / (now - fps_last);
Log.i(TAG, "fps: " + fps);
fps_max_count = (int) (5.f * fps);
}
fps_count = fps_max_count;
fps_last = now;
}
try {
if (bufferWorks) {
camAddCbBuffer.invoke(mCamera, buffer);
} else {
mCamera.setOneShotPreviewCallback(mPreviewHandler);
}
} catch (Exception e) {
Log.e(TAG, "addCallbackBuffer failed: " + e);
}
}
private static final Method getCamAddCallbackBuffer() {
try {
return Class.forName("android.hardware.Camera").getMethod("addCallbackBuffer", byte[].class);
} catch (Exception e) {
Log.e(TAG, "No addCallbackBuffer: " + e);
}
return null;
}
private static final Method getCamSetPreviewCallbackWithBuffer() {
try {
return Class.forName("android.hardware.Camera").getMethod("setPreviewCallbackWithBuffer",
Camera.PreviewCallback.class);
} catch (Exception e) {
Log.e(TAG, "No setPreviewCallbackWithBuffer: " + e);
}
return null;
}
protected class PreviewHandler extends HandlerThread implements Camera.PreviewCallback {
private Handler mHandler;
private boolean stopped = false;
PreviewHandler(String name) {
super(name);
mHandler = null;
start();
}
@Override
public void onPreviewFrame(final byte[] data, final Camera camera) {
synchronized (this) {
if (mHandler != null && camera == mCamera) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (!stopped) {
processFrame(data);
if (mHandler != null) {
addCallbackBuffer(data);
}
}
}
});
}
}
}
@Override
synchronized protected void onLooperPrepared() {
synchronized (this) {
Log.v(TAG, "onLooperPrepared()");
if (stopped == false) {
mHandler = new Handler();
Log.d(TAG, "frame processing start");
setPreviewCallbackWithBuffer(this);
}
}
}
synchronized private void stopPreview() {
synchronized (this) {
stopped = true;
if (mHandler != null) {
Log.d(TAG, "frame processing stop");
setPreviewCallbackWithBuffer(null);
mHandler = null;
}
}
}
}
private static final Method camAddCbBuffer = getCamAddCallbackBuffer();
private static final Method camSetPreview = getCamSetPreviewCallbackWithBuffer();
private static final boolean bufferWorks = camAddCbBuffer != null && camSetPreview != null;
}