1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18package com.example.android.rs.sto; 19 20import android.graphics.SurfaceTexture; 21import android.hardware.Camera; 22import android.os.SystemClock; 23import android.util.Log; 24 25import java.io.IOException; 26import java.util.List; 27 28public class CameraCapture { 29 30 public interface CameraFrameListener { 31 public void onNewCameraFrame(); 32 } 33 34 static final int FRAMES_PER_SEC = 30; 35 36 private Camera mCamera; 37 private SurfaceTexture mSurfaceTexture; 38 39 private int mProgram; 40 41 private int mCameraTransformHandle; 42 private int mTexSamplerHandle; 43 private int mTexCoordHandle; 44 private int mPosCoordHandle; 45 46 private float[] mCameraTransform = new float[16]; 47 48 private int mCameraId = 0; 49 private int mWidth; 50 private int mHeight; 51 52 private long mStartCaptureTime = 0; 53 54 private boolean mNewFrameAvailable = false; 55 private boolean mIsOpen = false; 56 57 private CameraFrameListener mListener; 58 59 public synchronized void beginCapture(int cameraId, int width, int height, 60 SurfaceTexture st) { 61 mCameraId = cameraId; 62 mSurfaceTexture = st; 63 64 // Open the camera 65 openCamera(width, height); 66 67 // Start the camera 68 mStartCaptureTime = SystemClock.elapsedRealtime(); 69 mCamera.startPreview(); 70 mIsOpen = true; 71 } 72 73 public void getCurrentFrame() { 74 if (checkNewFrame()) { 75 if (mStartCaptureTime > 0 && SystemClock.elapsedRealtime() - mStartCaptureTime > 2000) { 76 // Lock white-balance and exposure for effects 77 Log.i("CC", "Locking white-balance and exposure!"); 78 Camera.Parameters params = mCamera.getParameters(); 79 params.setAutoWhiteBalanceLock(true); 80 params.setAutoExposureLock(true); 81 //mCamera.setParameters(params); 82 mStartCaptureTime = 0; 83 } 84 85 mSurfaceTexture.updateTexImage(); 86 mSurfaceTexture.getTransformMatrix(mCameraTransform); 87 88 // display it here 89 } 90 } 91 92 public synchronized boolean hasNewFrame() { 93 return mNewFrameAvailable; 94 } 95 96 public synchronized void endCapture() { 97 mIsOpen = false; 98 if (mCamera != null) { 99 mCamera.release(); 100 mCamera = null; 101 mSurfaceTexture = null; 102 } 103 } 104 105 public synchronized boolean isOpen() { 106 return mIsOpen; 107 } 108 109 public int getWidth() { 110 return mWidth; 111 } 112 113 public int getHeight() { 114 return mHeight; 115 } 116 117 public void setCameraFrameListener(CameraFrameListener listener) { 118 mListener = listener; 119 } 120 121 private void openCamera(int width, int height) { 122 // Setup camera 123 mCamera = Camera.open(mCameraId); 124 mCamera.setParameters(calcCameraParameters(width, height)); 125 126 // Create camera surface texture 127 try { 128 mCamera.setPreviewTexture(mSurfaceTexture); 129 } catch (IOException e) { 130 throw new RuntimeException("Could not bind camera surface texture: " + 131 e.getMessage() + "!"); 132 } 133 134 // Connect SurfaceTexture to callback 135 mSurfaceTexture.setOnFrameAvailableListener(onCameraFrameAvailableListener); 136 } 137 138 private Camera.Parameters calcCameraParameters(int width, int height) { 139 Camera.Parameters params = mCamera.getParameters(); 140 params.setPreviewSize(mWidth, mHeight); 141 142 // Find closest size 143 int closestSize[] = findClosestSize(width, height, params); 144 mWidth = closestSize[0]; 145 mHeight = closestSize[1]; 146 params.setPreviewSize(mWidth, mHeight); 147 148 // Find closest FPS 149 int closestRange[] = findClosestFpsRange(FRAMES_PER_SEC, params); 150 151 params.setPreviewFpsRange(closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], 152 closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 153 154 return params; 155 } 156 157 private int[] findClosestSize(int width, int height, Camera.Parameters parameters) { 158 List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes(); 159 int closestWidth = -1; 160 int closestHeight = -1; 161 int smallestWidth = previewSizes.get(0).width; 162 int smallestHeight = previewSizes.get(0).height; 163 for (Camera.Size size : previewSizes) { 164 // Best match defined as not being larger in either dimension than 165 // the requested size, but as close as possible. The below isn't a 166 // stable selection (reording the size list can give different 167 // results), but since this is a fallback nicety, that's acceptable. 168 if ( size.width <= width && 169 size.height <= height && 170 size.width >= closestWidth && 171 size.height >= closestHeight) { 172 closestWidth = size.width; 173 closestHeight = size.height; 174 } 175 if ( size.width < smallestWidth && 176 size.height < smallestHeight) { 177 smallestWidth = size.width; 178 smallestHeight = size.height; 179 } 180 } 181 if (closestWidth == -1) { 182 // Requested size is smaller than any listed size; match with smallest possible 183 closestWidth = smallestWidth; 184 closestHeight = smallestHeight; 185 } 186 int[] closestSize = {closestWidth, closestHeight}; 187 return closestSize; 188 } 189 190 private int[] findClosestFpsRange(int fps, Camera.Parameters params) { 191 List<int[]> supportedFpsRanges = params.getSupportedPreviewFpsRange(); 192 int[] closestRange = supportedFpsRanges.get(0); 193 int fpsk = fps * 1000; 194 int minDiff = 1000000; 195 for (int[] range : supportedFpsRanges) { 196 int low = range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX]; 197 int high = range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]; 198 if (low <= fpsk && high >= fpsk) { 199 int diff = (fpsk - low) + (high - fpsk); 200 if (diff < minDiff) { 201 closestRange = range; 202 minDiff = diff; 203 } 204 } 205 } 206 Log.i("CC", "Found closest range: " 207 + closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] + " - " 208 + closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 209 return closestRange; 210 } 211 212 private synchronized void signalNewFrame() { 213 mNewFrameAvailable = true; 214 if (mListener != null) { 215 mListener.onNewCameraFrame(); 216 } 217 } 218 219 private synchronized boolean checkNewFrame() { 220 if (mNewFrameAvailable) { 221 mNewFrameAvailable = false; 222 return true; 223 } 224 return false; 225 } 226 227 private SurfaceTexture.OnFrameAvailableListener onCameraFrameAvailableListener = 228 new SurfaceTexture.OnFrameAvailableListener() { 229 @Override 230 public void onFrameAvailable(SurfaceTexture surfaceTexture) { 231 signalNewFrame(); 232 } 233 }; 234} 235