I'm trying to use CameraPreview in activity but when I try to use this android studio gets an error. what is my problem?
You need to create a CameraPreview class in the same folder as your MainActivity.
Here's the code for my preview, you'll have to add some code to your MainActivity as well and maybe edit my code to work with your project.
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = CameraPreview.class.getSimpleName();
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
private Context mContext;
private List mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public CameraPreview(Context context) {
super(context);
}
public CameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setCameraPreview(Context context, Camera camera) {
mContext = context;
mCamera = camera;
if(mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
}
requestLayout();
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mSurfaceHolder.setKeepScreenOn(true);
}
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (IOException e) {
Log.d("DG_DEBUG", "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
if (mSurfaceHolder.getSurface() == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
e.printStackTrace();
// ignore: tried to stop a non-existent preview
}
try {
Camera.Parameters cameraParameters = mCamera.getParameters();
List<String> focusModes = cameraParameters.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
cameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}
List<Camera.Size> previewSizes = cameraParameters.getSupportedPreviewSizes();
// List<Camera.Size> pictureSizes = cameraParameters.getSupportedPictureSizes();
Camera.Size optimalPreviewSize = getOptimalSize(previewSizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
// Camera.Size optimalPictureSize = getOptimalSize(pictureSizes, getResources().getDisplayMetrics().heightPixels, getResources().getDisplayMetrics().widthPixels);
cameraParameters.setPreviewSize(optimalPreviewSize.width, optimalPreviewSize.height);
// cameraParameters.setPictureSize(optimalPictureSize.width, optimalPictureSize.height);
mCamera.setParameters(cameraParameters);
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "Error setting camera preview" + e.getMessage());
mCamera.release();
mCamera = null;
}
}
private Camera.Size getOptimalSize(List<Camera.Size> sizes, int h, int w) {
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) w/h;
if (sizes == null) {
return null;
}
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.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 (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if (mCamera != null) {
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
e.printStackTrace();
// ignore: tried to stop a non-existent preview
}
}
}
}
Related
I'm using a Custom Camera for my app for AR View. The Camera preview is getting stretched on full screen portrait mode.
I have tried many solutions on stackoverflow but it's not working for my code.
Can anyone please tell me how to fix this?
I have added my camera working code and a screenshot below where the preview is getting stretched.
This is my Custom Camera Class:
public class ARCamera extends ViewGroup implements SurfaceHolder.Callback {
private final static float Z_NEAR = 0.5f;
private final static float Z_FAR = 2000;
private final String TAG = ARCamera.class.getSimpleName();
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
Camera camera;
Activity activity;
float[] projectionMatrix = new float[16];
int cameraWidth;
int cameraHeight;
int screenWidth, screenHeight;
int rotation;
public ARCamera(Context context, SurfaceView surfaceView) {
super(context);
this.surfaceView = surfaceView;
this.activity = (Activity) context;
surfaceHolder = this.surfaceView.getHolder();
surfaceHolder.addCallback(this);
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
rotation = windowManager.getDefaultDisplay()
.getRotation();
this.screenWidth = displayMetrics.widthPixels;
this.screenHeight = displayMetrics.heightPixels;
}
public void setCamera(Camera camera) {
this.camera = camera;
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
public void surfaceCreated(SurfaceHolder holder) {
try {
if (camera != null) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
camera.setDisplayOrientation((info.orientation - degrees + 360) % 360);
camera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera = null;
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (camera != null) {
this.cameraWidth = width;
this.cameraHeight = height;
Camera.Parameters parameters = camera.getParameters();
try {
List<Camera.Size> supportedSizes = camera.getParameters().getSupportedPreviewSizes();
for (Camera.Size element : supportedSizes) {
element.width -= cameraWidth;
element.height -= cameraHeight;
}
Collections.sort(supportedSizes, new ResolutionOrders());
parameters.setPreviewSize(width + supportedSizes.get(supportedSizes.size() - 1).width, height + supportedSizes.get(supportedSizes.size() - 1).height);
} catch (Exception ex) {
parameters.setPreviewSize(screenWidth, screenHeight);
}
this.camera.setParameters(parameters);
this.camera.startPreview();
generateProjectionMatrix();
}
}
private void generateProjectionMatrix() {
float ratio = (float) this.screenWidth / this.screenHeight;
final int OFFSET = 0;
final float LEFT = -ratio;
final float RIGHT = ratio;
final float BOTTOM = -1;
final float TOP = 1;
Matrix.frustumM(projectionMatrix, OFFSET, LEFT, RIGHT, BOTTOM, TOP, Z_NEAR, Z_FAR);
}
public float[] getProjectionMatrix() {
return projectionMatrix;
}
class ResolutionOrders implements java.util.Comparator<Camera.Size> {
public int compare(Camera.Size left, Camera.Size right) {
return Float.compare(left.width + left.height, right.width + right.height);
}
}
}
In the surface changed block, you have to choose the optimal size according to your device programmatically.
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
this will give you total supported camera sizes. you have to choose appropriate size from this. I have use the function called "chooseOptimalSize".
Size aspectRatio = new Size(matrix.widthPixels, matrix.heightPixels);
Camera.Size previewSize = chooseOptimalSize(previewSizes, PREFERRED_PREVIEW_WIDTH, PREFERRED_PREVIEW_HEIGHT, aspectRatio, this);
This is the function "chooseOptimalSize":-
public static Camera.Size chooseOptimalSize(List<Camera.Size> choices, int width, int height, Size aspectRatio, Context c) {
// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
double ratio = (double) h / w;
int loopCounter=0;
for (Camera.Size size : choices) {
int orientation = c.getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
//if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=720) {
//if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=3840 ) {
//if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=5120 ) {//Retina 5K
if((size.width/16) == (size.height/9) && size.width <=7680 ) {//8K UHDTV Super Hi-Vision
Log.e(TAG, "chooseOptimalSize:"+size+"--LoopPosition---==>"+loopCounter);
return size;
}
} else {
Log.e(TAG, "chooseOptimalSize:--given--"+size);
if((size.width/16) == (size.height/9) && ((size.width <=1280)||(size.height<=1920))) {
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=4320 ) ) {//8K UHDTV Super Hi-Vision
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=2880 ) ) {//Retina 5K
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=2160 ) ) {
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=1280 ) ) {
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=4480 && size.getWidth() >=1280) ) {
Log.e(TAG, "chooseOptimalSize:"+size+"-16:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((size.width/18) == (size.height/9) && ((size.width <=3840)||(size.height<=2160))) {
Log.e(TAG, "chooseOptimalSize:"+size+"-18:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((size.width/18.5) == (size.height/9) && ((size.width <=3840)||(size.height<=2160))) {
Log.e(TAG, "chooseOptimalSize:"+size+"-18.5:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((width/19) == (height/9) && ((width <=3840)||(height<=2160))) {
/*if((size.getWidth()/19) == (size.getHeight()/9) && ((size.getWidth() <=3840)||(size.getHeight()<=2160))) {*/
Log.e(TAG, "chooseOptimalSize:"+size+"-19:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((size.width/19.5) == (size.height/9) && ((size.width<=3840)||(size.height<=2160))) {
Log.e(TAG, "chooseOptimalSize:"+size+"-19.5:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else{
Log.e(TAG, "chooseOptimalSize"+" not proper aspect resolution");
}
//2340
}
// if(screenWidth==size.getWidth()){
// Log.e(TAG1, loopCounter+".choose:width Matched:"+screenWidth+"="+size.getWidth());
// }else{
// Log.e(TAG1, loopCounter+".choose:width Not Matched:"+screenWidth+"="+size.getWidth());
// }
//
// if(screenHeight==size.getHeight()){
// Log.e(TAG1, loopCounter+".choose:height Matched:"+screenHeight+"="+size.getHeight());
// }else{
// Log.e(TAG1, loopCounter+".choose:height Not Matched:"+screenHeight+"="+size.getHeight());
// }
loopCounter++;
}
// Pick the smallest of those, assuming we found any
// if (bigEnough.size() > 0) {
// return Collections.min(bigEnough, new CompareSizesByArea());
// } else {
// Log.e(TAG, "Couldn't find any suitable preview size");
return choices.get(0);
// }
}
/*
* Compares two {#code Size}s based on their areas.
*/
static class CompareSizesByArea implements Comparator<Size> {
#Override
public int compare(Size lhs, Size rhs) {
// We cast here to ensure the multiplications won't overflow
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
you can uncomment the code if you want in my case there is no need of that code.
This function will give you optimal size of the device's camera. you can set that using :
parameters.setPreviewSize(previewSize.width,previewSize.height);
and you are done !!!
I want to implement zoom function while video recording in android.But, I am not able to access Camera parameters or Camera startSmoothZoom() method in neither main activity nor surface class. If you access camera parametera in media recorder method(prepareMediaRecorder()) it will throw null pointer exception.
this activity class- in prepareMediaRecorder() method not able to access camera parameters and also not able to set startSmoothZoom(). here camera object giving null pointer exception.
public class CustomCameraPreview extends BaseActivity implements
OnClickListener, AlertPositiveListener, OrientationListener,
ActivityCompat.OnRequestPermissionsResultCallback {
RelativeLayout mLayout;
MediaRecorder mediaRecorder;
private PictureCallback mPictureCallback = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
cameraData = data;
captureAngle = getRotation();
mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
catch (OutOfMemoryError e){
System.gc();
mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
// int rotation=getRotation();
Matrix matrix = new Matrix();
matrix.postRotate(getRotation());
/*mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(),
mBitmap.getHeight(), matrix, true);*/
mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(),
mBitmap.getHeight(), matrix, false);
if (mBitmap != null) {
mButtonRetake.setEnabled(true);
} else {
Message.displayToast(CustomCameraPreview.this,
getString(R.string.picture_not_taken));
}
mCamera.release();
mButtonCapture.setEnabled(false);
}
};
protected void onCreate(){
initiCameraForVideo();
}
private void initiCameraForVideo() {
params = mCamera.getParameters();
mButtonCapture.setBackgroundResource(R.drawable.videostart);
mShowCamera = new CameraSurfaceHolder(CustomCameraPreview.this,
mCamera);
mLayout = (RelativeLayout) findViewById(R.id.relativeLayout);
mLayout.removeAllViews();
mLayout.addView(mShowCamera);
List<Camera.Size> mSizeList_Video = null;// params.getSupportedPreviewSizes();
if (params.getSupportedVideoSizes() != null) {
mSizeList_Video = params.getSupportedVideoSizes();
} else {
// Video sizes may be null, which indicates that all the
// supported preview sizes are supported for video
// recording.
mSizeList_Video = mCamera.getParameters()
.getSupportedPreviewSizes();
}
}
#Override
public void onClick(View v) {
int viewId = v.getId();
switch (viewId) {
case R.id.button_Capture:
releaseCamera();
if (!prepareMediaRecorder()) {
Message.displayToast(
CustomCameraPreview.this,
getString(R.string.somethign_went_wrong));
} else {
mediaRecorder.start();
recording = true;
}
}
private boolean prepareMediaRecorder() \*method to setup media player to record video
{
mCamera = isCameraAvailable();
mediaRecorder = new MediaRecorder();
mCamera.unlock();
mediaRecorder.setCamera(mCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
if(CamcorderProfile.hasProfile(findCameraID(), CamcorderProfile.QUALITY_480P)) {
mediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_480P));
}else{
mediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_LOW));
}
mediaRecorder.setOutputFile(getOutputVideoFile());
mediaRecorder.setMaxDuration(60000);
// mediaRecorder.setMaxFileSize(100 * 1000 * 1000);
mediaRecorder.setPreviewDisplay(mShowCamera.getHolder().getSurface());
try {
mediaRecorder.prepare();
}
}
#Override
protected void onPause() {
super.onPause();
releaseMediaRecorder();
releaseCamera();
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
and this surface preview class-
public class CameraSurfaceHolder extends SurfaceView implements
SurfaceHolder.Callback {
private static final String TAG = "CameraSurfaceHolder";
Context mContext;
private String errorMessage = "";
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
public CameraSurfaceHolder(Context context, Camera camera) {
super(context);
mContext = context;
mCamera = camera;
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
/*if (holder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
setCameraDisplayOrientation((Activity)mContext, Camera.CameraInfo.CAMERA_FACING_BACK, mCamera);
// start preview with new settings
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
*/
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
} catch (Exception e) {
Logger.ex(e);
}
}
public void setCameraDisplayOrientation(Activity activity, int cameraId,
Camera camera) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
/*Display mDisplay = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int rotation = mDisplay.getDisplayId();*/
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
Camera.Parameters mParameters = camera.getParameters();
mParameters.setRotation(rotation);
camera.setDisplayOrientation(result);
camera.setParameters(mParameters);
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
in above class I added some code like below and when user touch on camera preview its throwing null pointer exception in onTouchEvent() on access of camera paramters. Also tried like I set again camera object to surface in activity after configure media recorder(prepareMediaRecorder()), but zoom function working but video is not recording.
#Override
public boolean onTouchEvent(MotionEvent event) {
// Get the pointer ID
Camera.Parameters params = mCamera.getParameters();
int action = event.getAction();
if (event.getPointerCount() > 1) {
// handle multi-touch events
if (action == MotionEvent.ACTION_POINTER_DOWN) {
mDist = getFingerSpacing(event);
} else if (action == MotionEvent.ACTION_MOVE && params.isZoomSupported()) {
mCamera.cancelAutoFocus();
handleZoom(event, params);
}
} else {
// handle single touch events
if (action == MotionEvent.ACTION_UP) {
handleFocus(event, params);
}
}
return true;
}
private void handleZoom(MotionEvent event, Camera.Parameters params) {
int maxZoom = params.getMaxZoom();
int zoom = params.getZoom();
float newDist = getFingerSpacing(event);
if (newDist > mDist) {
//zoom in
if (zoom < maxZoom)
zoom++;
} else if (newDist < mDist) {
//zoom out
if (zoom > 0)
zoom--;
}
mDist = newDist;
params.setZoom(zoom);
mCamera.setParameters(params);
}
public void handleFocus(MotionEvent event, Camera.Parameters params) {
int pointerId = event.getPointerId(0);
int pointerIndex = event.findPointerIndex(pointerId);
// Get the pointer's current position
float x = event.getX(pointerIndex);
float y = event.getY(pointerIndex);
List<String> supportedFocusModes = params.getSupportedFocusModes();
if (supportedFocusModes != null && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
mCamera.autoFocus(new Camera.AutoFocusCallback() {
#Override
public void onAutoFocus(boolean b, Camera camera) {
// currently set to auto-focus on single touch
}
});
}
}
/** Determine the space between the first two fingers */
private float getFingerSpacing(MotionEvent event) {
// ...
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float)Math.sqrt(x * x + y * y);
}
I'm trying to make a motion detector app that captures images on the motion detection. Its working fine & saving the images. The problem is that the app crashes when I press back button from the camera activity to return to the home activity. How to fix it ?
Here is my code:
public class MotionDetectionActivity extends SensorsActivity {
private static final String TAG = "MotionDetectionActivity";
private static final String ENABLE_MOTION_DETECTION="switch_md";
private static SurfaceView preview = null;
private static SurfaceHolder previewHolder = null;
private static Camera camera = null;
private static boolean inPreview = false;
private static long mReferenceTime = 0;
private static IMotionDetection detector = null;
public static MediaPlayer song;
public static Vibrator mVibrator;
private static volatile AtomicBoolean processing = new AtomicBoolean(false);
public int MY_PERMISSIONS_REQUEST_CAMERA;
/**
* {#inheritDoc}
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.main);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
boolean enablemotionpref = sharedPref.getBoolean(ENABLE_MOTION_DETECTION, true);
song = MediaPlayer.create(this, R.raw.sound);
mVibrator = (Vibrator)this.getSystemService(VIBRATOR_SERVICE);
preview = (SurfaceView) findViewById(R.id.preview);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
if (enablemotionpref) {
if (Preferences.USE_RGB) {
detector = new RgbMotionDetection();
} else if (Preferences.USE_LUMA) {
detector = new LumaMotionDetection();
} else {
// Using State based (aggregate map)
detector = new AggregateLumaMotionDetection();
}
}
}
/**
* {#inheritDoc}
*/
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
/**
* {#inheritDoc}
*/
#Override
public void onPause() {
super.onPause();
if(song!=null && song.isPlaying())
{
song.stop();}
camera.setPreviewCallback(null);
if (inPreview) camera.stopPreview();
inPreview = false;
camera.release();
camera = null;
}
/**
* {#inheritDoc}
*/
#Override
public void onResume() {
super.onResume();
camera = Camera.open();
}
private PreviewCallback previewCallback = new PreviewCallback() {
/**
* {#inheritDoc}
*/
#Override
public void onPreviewFrame(byte[] data, Camera cam) {
if (data == null) return;
Camera.Size size = cam.getParameters().getPreviewSize();
if (size == null) return;
if (!GlobalData.isPhoneInMotion()) {
DetectionThread thread = new DetectionThread(data, size.width, size.height);
thread.start();
}
}
};
private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
/**
* {#inheritDoc}
*/
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(previewHolder);
camera.setPreviewCallback(previewCallback);
} catch (Throwable t) {
Log.e("Callback", "Exception in setPreviewDisplay()", t);
}
}
/**
* {#inheritDoc}
*/
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
Log.d(TAG, "Using width=" + size.width + " height=" + size.height);
}
camera.setParameters(parameters);
camera.startPreview();
inPreview = true;
}
/**
* {#inheritDoc}
*/
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Ignore
}
};
private static Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) result = size;
}
}
}
return result;
}
private static final class DetectionThread extends Thread {
private byte[] data;
private int width;
private int height;
public DetectionThread(byte[] data, int width, int height) {
this.data = data;
this.width = width;
this.height = height;
}
/**
* {#inheritDoc}
*/
#Override
public void run() {
if (!processing.compareAndSet(false, true)) return;
// Log.d(TAG, "BEGIN PROCESSING...");
try {
// Previous frame
int[] pre = null;
if (Preferences.SAVE_PREVIOUS) pre = detector.getPrevious();
// Current frame (with changes)
// long bConversion = System.currentTimeMillis();
int[] img = null;
if (Preferences.USE_RGB) {
img = ImageProcessing.decodeYUV420SPtoRGB(data, width, height);
if (img != null && detector.detect(img, width, height))
{
if(song!=null && !song.isPlaying())
{
song.start();
mVibrator.vibrate(50);
}
}
else
{
if(song!=null && song.isPlaying())
{
song.pause();
}
}
}
// Current frame (without changes)
int[] org = null;
if (Preferences.SAVE_ORIGINAL && img != null) org = img.clone();
if (img != null && detector.detect(img, width, height)) {
// The delay is necessary to avoid taking a picture while in
// the
// middle of taking another. This problem can causes some
// phones
// to reboot.
long now = System.currentTimeMillis();
if (now > (mReferenceTime + Preferences.PICTURE_DELAY)) {
mReferenceTime = now;
Bitmap previous = null;
if (Preferences.SAVE_PREVIOUS && pre != null) {
if (Preferences.USE_RGB) previous = ImageProcessing.rgbToBitmap(pre, width, height);
else previous = ImageProcessing.lumaToGreyscale(pre, width, height);
}
Bitmap original = null;
if (Preferences.SAVE_ORIGINAL && org != null) {
if (Preferences.USE_RGB) original = ImageProcessing.rgbToBitmap(org, width, height);
else original = ImageProcessing.lumaToGreyscale(org, width, height);
}
Bitmap bitmap = null;
if (Preferences.SAVE_CHANGES) {
if (Preferences.USE_RGB) bitmap = ImageProcessing.rgbToBitmap(img, width, height);
else bitmap = ImageProcessing.lumaToGreyscale(img, width, height);
}
Log.i(TAG, "Saving.. previous=" + previous + " original=" + original + " bitmap=" + bitmap);
Looper.prepare();
new SavePhotoTask().execute(previous, original, bitmap);
} else {
Log.i(TAG, "Not taking picture because not enough time has passed since the creation of the Surface");
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
processing.set(false);
}
// Log.d(TAG, "END PROCESSING...");
processing.set(false);
}
};
private static final class SavePhotoTask extends AsyncTask<Bitmap, Integer, Integer> {
/**
* {#inheritDoc}
*/
#Override
protected Integer doInBackground(Bitmap... data) {
for (int i = 0; i < data.length; i++) {
Bitmap bitmap = data[i];
String name = "MotDet_"+String.valueOf(System.currentTimeMillis());
if (bitmap != null) createDirectoryAndSaveFile(name, bitmap);
}
return 1;
}
private void createDirectoryAndSaveFile(String name, Bitmap bitmap) {
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "MD");//here you have created different name
boolean success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (success) {
// Do something on success
} else {
// Do something else on failure
}
File photo = new File(folder.getAbsolutePath(), name+ ".jpg"); //use path of above created folder
if (photo.exists()) {
photo.delete();
}
try {
FileOutputStream out = new FileOutputStream(photo.getPath());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
HomeActivity
public class HomeActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.home_layout);
Button bt1 = (Button) findViewById(R.id.button);
Button bt2= (Button)findViewById(R.id.button1);
bt1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(view.getContext(), MotionDetectionActivity.class);
startActivity(i);
}
});
bt2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View vew) {
Intent b=new Intent(vew.getContext(),SettingsActivity.class);
startActivity(b);
}
});
}
}
Stacktrace
handle like this an see if it still crashes
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if(camera != null) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
Log.d(TAG, "Using width=" + size.width + " height=" + size.height);
}
camera.setParameters(parameters);
camera.startPreview();
inPreview = true;
}
}
I'm trying to build a custom Camera in Android without using the Camera API (Using intents). I have a MainActivity.java, I need to call the CameraPreview class in order to see the camera preview, but I don't know how to call that class.
I tried
public CameraPreview cameraPreview;
and later
mPreview = new CameraPreview(this, mCamera);
if(hasCamera) {
// Create an instance of Camera
mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
It doesn't work. Please advice!
My code compiles but I don't see the preview on screen.
public class MainActivity extends AppCompatActivity implements SensorEventListener{
public CameraPreview cameraPreview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hasCamera = checkCameraHardware(this);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
// Success! There's a accelerometer.
mAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Toast.makeText(MainActivity.this, "Accelerometer Found!", Toast.LENGTH_SHORT).show();
}
else {
// Failure! No accelerometer.
Toast.makeText(MainActivity.this, "Accelerometer Not Found!", Toast.LENGTH_SHORT).show();
}
if(hasCamera) {
// Create an instance of Camera
mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
/* Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
// get an image from the camera
mCamera.takePicture(null, null, mPicture);
}
}
); */
}
//Accelerometer Handling
mAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccel, SensorManager.SENSOR_DELAY_NORMAL);
if(safeToTakePicture) {
// cameraPreview.surfaceCreated(mHolder);
mCamera.takePicture(null, null, mPicture);
safeToTakePicture = false;
}
}
#Override
public void onSensorChanged(SensorEvent event) {
long currentTime = System.currentTimeMillis();
// update every 1 sec
if((currentTime - prevTime) > 10000){
mDiff = currentTime - prevTime;
mX = event.values[0];
mY = event.values[1];
mZ = event.values[2];
float speed = Math.abs(mX + mY + mZ - mPrev_x - mPrev_y - mPrev_z) / mDiff;
if (speed > SHAKE_THRESHOLD) {
Log.d("sensor", "Shake detected with speed: " + speed);
mCamera.takePicture(null, null, mPicture);
safeToTakePicture = false;
Toast.makeText(this, "Shake detected with speed: " + speed, Toast.LENGTH_SHORT).show();
}
}
mPrev_x = mX;
mPrev_y = mY;
mPrev_z = mZ;
prevTime = currentTime;
// mCamera.takePicture(null, null, mPicture);
// Toast.makeText(MainActivity.this, "SensorChanged Event! x:" + event.values[0], Toast.LENGTH_SHORT).show();
}
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/** A safe way to get an instance of the Camera object. */
//Deprecated Camera instance, but ok
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
// receive data in a JPEG format,
// you must implement an Camera.PictureCallback interface to receive the image data and write it to a file
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d(TAG, "Error creating media file, check storage permissions: " /* +
e.getMessage()*/);
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
};
private static File getOutputMediaFile(int type){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyCameraApp");
// This location works best if you want the created images to be shared
// between applications and persist after your app has been uninstalled.
// Create the storage directory if it does not exist
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
public final void onAccuracyChanged(Sensor sensor, int accuracy){
//mCamera.takePicture(null, null, mPicture);
//Toast.makeText(this, "Taking a picture now", Toast.LENGTH_SHORT).show();
}
#Override
protected void onPause() {
super.onPause();
letGo();
}
#Override
protected void onDestroy() {
super.onDestroy();
letGo();
}
private void letGo(){
if(mCamera != null){
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
// Call stopPreview() to stop updating the preview surface.
mCamera.stopPreview();
}
}
/**
* When this function returns, mCamera will be null.
*/
private void stopPreviewAndFreeCamera() {
if (mCamera != null) {
// Call stopPreview() to stop updating the preview surface.
mCamera.stopPreview();
// Important: Call release() to release the camera for use by other
// applications. Applications should release the camera immediately
// during onPause() and re-open() it during onResume()).
mCamera.release();
mCamera = null;
}
}
}
CameraPreview
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private static final String TAG = MainActivity.class.getSimpleName();
SurfaceView mSurfaceView;
private Camera mCamera;
private boolean safeToTakePicture = false;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mSurfaceView = new SurfaceView(context);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
safeToTakePicture = true;
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
Ok guys, sharing my stable variant,
Here is improved Custom camera preview class (make attention! preview size set to 800x600 and image size around 5mpx for better performance, this can be removed, look in code):
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private Context mContext;
private Camera.PreviewCallback previewCallback;
private Camera.AutoFocusCallback autoFocusCallback;
private static final String TAG = "CameraPreview";
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public CameraPreview(Context context, Camera camera,
Camera.PreviewCallback previewCb,
Camera.AutoFocusCallback autoFocusCb) {
super(context);
mContext = context;
mCamera = camera;
previewCallback = previewCb;
autoFocusCallback = autoFocusCb;
// supported preview sizes
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
// for(Camera.Size str: mSupportedPreviewSizes)
// Log.e(TAG, str.width + "/" + str.height);
// for(Camera.Size str: mCamera.getParameters().getSupportedPictureSizes())
// Log.e(TAG, str.width + "/" + str.height);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
// // deprecated setting, but required on Android versions prior to 3.0
// mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
/*
* Set camera to continuous focus if supported, otherwise use
* software auto-focus. Only works for API level >=9.
*/
/*
Camera.Parameters parameters = camera.getParameters();
for (String f : parameters.getSupportedFocusModes()) {
if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
mCamera.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
autoFocusCallback = null;
break;
}
}
*/
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
Log.d("DBG", "Error setting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
/*
* If your preview can change or rotate, take care of those events here.
* Make sure to stop the preview before resizing or reformatting it.
*/
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
try {
// Hard code camera surface rotation 90 degs to match Activity view in portrait
// Camera.Parameters parameters = mCamera.getParameters();
// parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
// mCamera.setParameters(parameters);
Camera.Parameters params = mCamera.getParameters();
for(Camera.Size str: params.getSupportedPictureSizes()) {
if (str.width >= 2400 && str.width <= 2600 && str.height >= 1800 && str.height <= 2000) {
params.setPictureSize(str.width, str.height);
Log.e("Picture size: ", str.width + "/" + str.height);
}
}
for(Camera.Size str: params.getSupportedPreviewSizes())
if(str.width == 800 && str.height == 600){
params.setPreviewSize(str.width, str.height);
Log.e("Preview size: ", str.width + "/" + str.height);
}
mCamera.setParameters(params);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
mCamera.autoFocus(autoFocusCallback);
if(!(SettingsService.settings.autofocusOn))
mCamera.cancelAutoFocus();
} catch (Exception e) {
Log.d("DBG", "Error starting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
this.getHolder().removeCallback(this);
try {
mCamera.stopPreview();
mCamera.release();
}catch(Exception e){
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
float ratio;
if(mPreviewSize.height >= mPreviewSize.width)
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
else
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
// One of these methods should be used, second method squishes preview slightly
setMeasuredDimension(width, (int) (width * ratio));
// setMeasuredDimension((int) (width * ratio), height);
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) h / w;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
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 (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
And here is usage in activity or fragment:
public class ScanFragment extends Fragment {
private View mFragmentView;
private static Camera mCamera;
private CameraPreview mPreview;
private Handler autoFocusHandler;
private Context mContext;
public boolean previewing = true;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mContext = (MainActivity)getActivity();
// Inflate the layout for this fragment
mFragmentView = inflater.inflate(R.layout.fragment_scan, container, false);
}
public void cameraPreviewStop(){
previewing = false;
if(mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
}
}
public void cameraPreviewStart(){
try {
if (mCamera != null) {
mCamera.setPreviewCallback(previewCb);
mCamera.startPreview();
previewing = true;
mCamera.autoFocus(autoFocusCB);
}else{
initControls();
cameraPreviewStart();
}
}catch (Exception e){
releaseCamera();
initControls();
cameraPreviewStart();
}
}
public void initControls() {
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
autoFocusHandler = new Handler();
try{
mCamera = getCameraInstance();
}catch(Exception e){
}
// Instance barcode scanner
initPreviewCamera();
}
public void initPreviewCamera(){
autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
autoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
mPreview = new CameraPreview(mContext, mCamera, previewCb,
autoFocusCB);
FrameLayout preview = (FrameLayout) mFragmentView.findViewById(R.id.cameraPreview);
preview.removeAllViews();
preview.addView(mPreview);
}
/**
* A safe way to get an instance of the Camera object.
*/
public static Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open();
} catch (Exception e) {
}
return c;
}
public void releaseCamera() {
if (mCamera != null) {
previewing = false;
try {
mCamera.setPreviewCallback(null);
mCamera.release();
}catch (Exception e){
}
mCamera = null;
}
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (previewing)
mCamera.autoFocus(autoFocusCB);
}
};
Camera.PreviewCallback previewCb = new Camera.PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
Image imageFromCamera = new Image(size.width, size.height, "Y800");
// Do something...
}
};
// Mimic continuous auto-focusing
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
autoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
}
If in activity then override some things:
#Override
protected void onResume() {
super.onResume();
if(previewing) {
initControls();
cameraPreviewStart();
}
}
#Override
protected void onStop() {
super.onStop();
releaseCamera();
}
And the fragment view with camera fragment (you can add here your custom views and anything you want to customize, size of preview, absolutely anything you want):
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:local="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:id="#+id/cameraPreview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
And final note, this is very important! Especially for Android api 23+ devices, from android 6.0 you must use only one instance of camera if you got null on camera object then you are trying to open camera that is already opened. Have a nice day ;)
I'm going to develop an android application using BeyondAR framework. I try to use a CameraView component at the first half of the screen (app running only in portrait mode), but when i rotate camera 90 degrees image stretches and aspect ratio is wrong.Any help?
CameraView class (Beyondar framework)
public class CameraView extends SurfaceView implements SurfaceHolder.Callback,
Camera.PictureCallback {
/**
*
* #author Joan Puig Sanz (joanpuigsanz#gmail.com)
*
*/
public static interface IPictureCallback {
/**
* This method is called when the snapshot of the camera is ready. If
* there is an error, the image will be null
*
* #param picture
*/
void onPictureTaken(Bitmap picture);
}
private SurfaceHolder mHolder;
private Camera mCamera;
private IPictureCallback mCameraCallback;
private BitmapFactory.Options mOptions;
private Size mPreviewSize;
private List<Size> mSupportedPreviewSizes;
private List<String> mSupportedFlashModes;
public CameraView(Context context) {
super(context);
init(context);
}
public CameraView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public CameraView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mHolder = getHolder();
mHolder.addCallback(this);
try {
mCamera = Camera.open();
//mCamera.setDisplayOrientation(90);
//Camera.Parameters params = mCamera.getParameters();
//params.setPreviewSize(427, 1240);
//mCamera.setParameters(params);
setCamera(mCamera);
} catch (Exception e) {
Log.e(Constants.TAG, "ERROR: Unable to open the camera", e);
}
if (android.os.Build.VERSION.SDK_INT <= 10) {// Android 2.3.x or lower
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
// Set the camera to Auto Flash mode.
if (mSupportedFlashModes != null
&& mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
//parameters.setPreviewSize(300, 200);
mCamera.setParameters(parameters);
}
}
}
public void setSupportedPreviewSizes(List<Size> supportedPreviewSizes) {
mSupportedPreviewSizes = supportedPreviewSizes;
}
public Size getPreviewSize() {
return mPreviewSize;
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera == null) {
init(getContext());
if (mCamera == null) {
return;
}
}
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
if (mCamera != null) {
mCamera.release();
}
mCamera = null;
Log.e(Constants.TAG, "CameraView -- ERROR en SurfaceCreated", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
// Because the CameraDevice object is not a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera == null) {
return;
}
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private Size getOptimalPreviewSize(List<Size> sizes, int width, int height) {
Size result = null;
for (Camera.Size size : sizes) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return result;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mCamera == null || getPreviewSize() == null) {
return;
}
Camera.Parameters parameters = mCamera.getParameters();
Size previewSize = getPreviewSize();
parameters.setPreviewSize(previewSize.width, previewSize.height);
mCamera.setParameters(parameters);
previewCamera();
}
#Override
public void onPictureTaken(byte[] imageData, Camera camera) {
if (imageData != null && mCameraCallback != null) {
mCameraCallback.onPictureTaken(StoreByteImage(imageData));
}
previewCamera();
}
public void previewCamera() {
if (mCamera == null){
return;
}
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(Constants.TAG, "Cannot start preview.", e);
}
}
private Bitmap StoreByteImage(byte[] imageData) {
Bitmap myImage = DebugBitmap.decodeByteArray(imageData, 0, imageData.length, mOptions);
imageData = null;
System.gc();
return myImage;
}
public void tackePicture(IPictureCallback cameraCallback) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
tackePicture(cameraCallback, options);
}
public void tackePicture(IPictureCallback cameraCallback, BitmapFactory.Options options) {
if (mCamera == null) {
return;
}
mCameraCallback = cameraCallback;
mCamera.takePicture(null, this, this);
mOptions = options;
}
}
Edit
MyLayout xml file
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:orientation="horizontal"
android:paddingBottom="#dimen/padding"
android:paddingLeft="#dimen/padding"
android:paddingRight="#dimen/padding"
android:paddingTop="#dimen/padding" >
<FrameLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.beyondar.android.opengl.views.BeyondarGLSurfaceView
android:id="#+id/customGLSurface"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.beyondar.android.views.CameraView
android:id="#+id/camera"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TextView
android:id="#+id/labelText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Touch an AR Object"
android:background="#000000"
android:textColor="#FFFFFF"
/>
</FrameLayout>
</LinearLayout
If you look at the example application for BeyondAR, you can see that it has a similar problem in that the camera's image gets stretched to fill the screen and so doesn't have the proper aspect ratio in both landscape in portrait. This is a common problem when working with the camera preview since it locks to a particular orientation when you first start it.
In order to get that, you need to resize the view on rotation to an aspect ratio that matches the device's camera. Here's the official Android guide.
Notice the part specifically called "Set the Preview Orientation".
BeyondAR has been updated, now it is way easier thanks to fragments. Check the web page and update your library:
https://github.com/BeyondAR/beyondar