Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 package org.ros.android.view.camera;
00018
00019 import com.google.common.base.Preconditions;
00020
00021 import android.content.Context;
00022 import android.graphics.ImageFormat;
00023 import android.hardware.Camera;
00024 import android.hardware.Camera.PreviewCallback;
00025 import android.hardware.Camera.Size;
00026 import android.util.AttributeSet;
00027 import android.view.SurfaceHolder;
00028 import android.view.SurfaceView;
00029 import android.view.View;
00030 import android.view.ViewGroup;
00031 import org.ros.exception.RosRuntimeException;
00032
00033 import java.io.IOException;
00034 import java.util.List;
00035
00041 public class CameraPreviewView extends ViewGroup {
00042
00043 private final static double ASPECT_TOLERANCE = 0.1;
00044
00045 private SurfaceHolder surfaceHolder;
00046 private Camera camera;
00047 private Size previewSize;
00048 private byte[] previewBuffer;
00049 private RawImageListener rawImageListener;
00050 private BufferingPreviewCallback bufferingPreviewCallback;
00051
00052 private final class BufferingPreviewCallback implements PreviewCallback {
00053 @Override
00054 public void onPreviewFrame(byte[] data, Camera camera) {
00055 Preconditions.checkArgument(camera == CameraPreviewView.this.camera);
00056 Preconditions.checkArgument(data == previewBuffer);
00057 if (rawImageListener != null) {
00058 rawImageListener.onNewRawImage(data, previewSize);
00059 }
00060 camera.addCallbackBuffer(previewBuffer);
00061 }
00062 }
00063
00064 private final class SurfaceHolderCallback implements SurfaceHolder.Callback {
00065 @Override
00066 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
00067 }
00068
00069 @Override
00070 public void surfaceCreated(SurfaceHolder holder) {
00071 try {
00072 if (camera != null) {
00073 camera.setPreviewDisplay(holder);
00074 }
00075 } catch (IOException e) {
00076 throw new RosRuntimeException(e);
00077 }
00078 }
00079
00080 @Override
00081 public void surfaceDestroyed(SurfaceHolder holder) {
00082 releaseCamera();
00083 }
00084 }
00085
00086 private void init(Context context) {
00087 SurfaceView surfaceView = new SurfaceView(context);
00088 addView(surfaceView);
00089 surfaceHolder = surfaceView.getHolder();
00090 surfaceHolder.addCallback(new SurfaceHolderCallback());
00091 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
00092 bufferingPreviewCallback = new BufferingPreviewCallback();
00093 }
00094
00095 public CameraPreviewView(Context context) {
00096 super(context);
00097 init(context);
00098 }
00099
00100 public CameraPreviewView(Context context, AttributeSet attrs) {
00101 super(context, attrs);
00102 init(context);
00103 }
00104
00105 public CameraPreviewView(Context context, AttributeSet attrs, int defStyle) {
00106 super(context, attrs, defStyle);
00107 init(context);
00108 }
00109
00110 public void releaseCamera() {
00111 if (camera == null) {
00112 return;
00113 }
00114 camera.setPreviewCallbackWithBuffer(null);
00115 camera.stopPreview();
00116 camera.release();
00117 camera = null;
00118 }
00119
00120 public void setRawImageListener(RawImageListener rawImageListener) {
00121 this.rawImageListener = rawImageListener;
00122 }
00123
00124 public Size getPreviewSize() {
00125 return previewSize;
00126 }
00127
00128 public void setCamera(Camera camera) {
00129 Preconditions.checkNotNull(camera);
00130 this.camera = camera;
00131 setupCameraParameters();
00132 setupBufferingPreviewCallback();
00133 camera.startPreview();
00134 try {
00135
00136 camera.setPreviewDisplay(surfaceHolder);
00137 } catch (IOException e) {
00138 throw new RosRuntimeException(e);
00139 }
00140 }
00141
00142 private void setupCameraParameters() {
00143 Camera.Parameters parameters = camera.getParameters();
00144 List<Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
00145 previewSize = getOptimalPreviewSize(supportedPreviewSizes, getWidth(), getHeight());
00146 parameters.setPreviewSize(previewSize.width, previewSize.height);
00147 parameters.setPreviewFormat(ImageFormat.NV21);
00148 camera.setParameters(parameters);
00149 }
00150
00151 private Size getOptimalPreviewSize(List<Size> sizes, int width, int height) {
00152 Preconditions.checkNotNull(sizes);
00153 double targetRatio = (double) width / height;
00154 double minimumDifference = Double.MAX_VALUE;
00155 Size optimalSize = null;
00156
00157
00158 for (Size size : sizes) {
00159 double ratio = (double) size.width / size.height;
00160 if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
00161 continue;
00162 }
00163 if (Math.abs(size.height - height) < minimumDifference) {
00164 optimalSize = size;
00165 minimumDifference = Math.abs(size.height - height);
00166 }
00167 }
00168
00169
00170 if (optimalSize == null) {
00171 minimumDifference = Double.MAX_VALUE;
00172 for (Size size : sizes) {
00173 if (Math.abs(size.height - height) < minimumDifference) {
00174 optimalSize = size;
00175 minimumDifference = Math.abs(size.height - height);
00176 }
00177 }
00178 }
00179
00180 Preconditions.checkNotNull(optimalSize);
00181 return optimalSize;
00182 }
00183
00184 private void setupBufferingPreviewCallback() {
00185 int format = camera.getParameters().getPreviewFormat();
00186 int bits_per_pixel = ImageFormat.getBitsPerPixel(format);
00187 previewBuffer = new byte[previewSize.height * previewSize.width * bits_per_pixel / 8];
00188 camera.addCallbackBuffer(previewBuffer);
00189 camera.setPreviewCallbackWithBuffer(bufferingPreviewCallback);
00190 }
00191
00192 @Override
00193 protected void onLayout(boolean changed, int l, int t, int r, int b) {
00194 if (changed && getChildCount() > 0) {
00195 final View child = getChildAt(0);
00196 final int width = r - l;
00197 final int height = b - t;
00198
00199 int previewWidth = width;
00200 int previewHeight = height;
00201 if (previewSize != null) {
00202 previewWidth = previewSize.width;
00203 previewHeight = previewSize.height;
00204 }
00205
00206
00207 if (width * previewHeight > height * previewWidth) {
00208 final int scaledChildWidth = previewWidth * height / previewHeight;
00209 child.layout((width - scaledChildWidth) / 2, 0, (width + scaledChildWidth) / 2, height);
00210 } else {
00211 final int scaledChildHeight = previewHeight * width / previewWidth;
00212 child.layout(0, (height - scaledChildHeight) / 2, width, (height + scaledChildHeight) / 2);
00213 }
00214 }
00215 }
00216 }