CameraPreviewView.java
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2011 Google Inc.
00003  * 
00004  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
00005  * use this file except in compliance with the License. You may obtain a copy of
00006  * the License at
00007  * 
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
00013  * License for the specific language governing permissions and limitations under
00014  * the License.
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       // This may have no effect if the SurfaceHolder is not yet created.
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     // Try to find a size that matches the aspect ratio and size.
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     // Cannot find one that matches the aspect ratio, ignore the requirement.
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       // Center the child SurfaceView within the parent.
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 }


android_core
Author(s): Damon Kohler
autogenerated on Thu Jun 6 2019 21:20:07