I'm creating a camera app that implements it's own camera preview for taking pictures.
The app is currently forced into portrait mode.
My problem is that the preview from the camera is slightly stretched (the aspect ratio is a bit off).
The funny thing is that I'm setting my SurfaceView size to always match the preview size. This ensures that the aspect ratio should always be perserved... but it isn't...
Here is the layout i use to show my camera preview:
public class Cp extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "CameraPreview";
private boolean mPreviewRunning = false;
private SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
private Size mPreviewSize;
private List<Size> mSupportedPreviewSizes;
private Camera mCamera;
public boolean IsPreviewRunning() {
return mPreviewRunning;
}
public Cp(Context context) {
this(context, null, 0);
}
public Cp(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public Cp(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
requestLayout();
}
}
public void switchCamera(Camera camera) {
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
camera.setParameters(parameters);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a wrapper to
// a SurfaceView that
// centers the camera preview instead of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes == null && mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters()
.getSupportedPreviewSizes();
}
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width,
height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
}
if (previewWidth == 0) {
previewWidth = 1;
}
if (previewHeight == 0) {
previewHeight = 1;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height
/ previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width
/ previewWidth;
child.layout(0, (height - scaledChildHeight) / 2, width,
(height + scaledChildHeight) / 2);
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where to
// draw.
try {
if (mCamera != null) {
Parameters params = mCamera.getParameters();
mSupportedPreviewSizes = params.getSupportedPreviewSizes();
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
stop();
}
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;
// Try to find an size match aspect ratio and size
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);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
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;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mCamera != null) {
// Now that the size is known, set up the camera parameters and
// begin the preview.
Camera.Parameters parameters = mCamera.getParameters();
if (mPreviewSize != null) {
parameters.setPreviewSize(mPreviewSize.width,
mPreviewSize.height);
}
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
mPreviewRunning = true;
}
}
public void stop() {
if (mCamera != null) {
mCamera.stopPreview();
mPreviewRunning = false;
mCamera = null;
}
}
}
Please note that in onLayout width and height are swapped because the app is always running in portrait.
I'm including some pictures to show you what the problem looks like:
I've debugged the code. The preview size is being set to 1280x720 and the size of the layout is also being correctly adjusted to match that size.
I've also tried different layouts but the result was always the same...
I was having the same problem, after some days in this puzzle, my Java class end up on this code:
So, The problem was happening because the camera display had a size (hight x width) 576x720, and my display was 1184x720. So, the camera preview (my surface view class) stretched to fill in the parent.
So, the approach that worked is to make this view bigger than my screen, and that just display the area of my screen. So, I had to use this weird frame combination (a relative layout inside a linearlayout), so that the size of the relative will be as big as I want - the surface view will fill in it -, and the linear will take just the part that I wanna display.
package com.example.frame.camera;
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.example.frame.MainActivity;
public class NativeCamera extends SurfaceView implements SurfaceHolder.Callback {
static private NativeCamera instance;
private LinearLayout frame = null;
private RelativeLayout innerFrame = null;
private Camera camera;
private final SurfaceHolder previewHolder;
private static final String TAG = "NativeCamera.java";
private boolean inPreview = false;
private boolean cameraConfigured = false;
private boolean frontCamera = false;
private Camera.Size size;
static public NativeCamera getInstance() {
if (NativeCamera.instance == null) {
if (MainActivity.debug) {
Log.d(TAG, "Creating Camera Singleton");
}
NativeCamera.instance = new NativeCamera(MainActivity.instance);
}
return NativeCamera.instance;
}
public void onResume() {
if (MainActivity.debug) {
Log.d(TAG, "onResume");
}
camera = Camera.open();
if (size != null) {
initPreview(size.width, size.height);
}
startPreview();
}
public void onPause() {
if (MainActivity.debug) {
Log.d(TAG, "onPause");
}
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera = null;
inPreview = false;
}
public void onDestroy() {
if (MainActivity.debug) {
Log.d(TAG, "onDestroy");
}
NativeCamera.instance = null;
}
public void onSwitch() {
frontCamera = !frontCamera;
if (inPreview) {
camera.stopPreview();
}
camera.release();
int cam = frontCamera ? 1 : 0;
camera = Camera.open(cam);
if (size != null) {
initPreview(size.width, size.height);
}
startPreview();
}
private NativeCamera(Context context) {
super(context);
// TODO Auto-generated constructor stub
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
previewHolder = getHolder();
previewHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
// previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
innerFrame = new RelativeLayout(MainActivity.instance);
innerFrame.addView(this);
frame = new LinearLayout(MainActivity.instance);
frame.addView(innerFrame);
}
public LinearLayout getFrame() {
return frame;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
if (MainActivity.debug) {
Log.d(TAG, "surfaceChanged");
}
initPreview(width, height);
startPreview();
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// no-op -- wait until surfaceChanged()
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
// no-op
}
private 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;
}
}
}
}
this.size = result;
return (result);
}
private void initPreview(int width, int height) {
if (camera != null && previewHolder.getSurface() != null) {
if (!cameraConfigured) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
cameraConfigured = true;
// Setting up correctly the view
double ratio = size.height / (double) size.width;
LayoutParams params = innerFrame.getLayoutParams();
params.height = MainActivity.size.y;
params.width = (int) (MainActivity.size.y * ratio);
innerFrame.setLayoutParams(params);
int deslocationX = (int) (params.width / 2.0 - MainActivity.size.x / 2.0);
innerFrame.animate().translationX(-deslocationX);
}
}
try {
camera.setPreviewDisplay(previewHolder);
camera.setDisplayOrientation(90);
} catch (Throwable t) {
Log.e(TAG, "Exception in setPreviewDisplay()", t);
Toast.makeText(MainActivity.instance, t.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
private void startPreview() {
if (MainActivity.debug) {
Log.d(TAG, "startPreview");
}
if (cameraConfigured && camera != null) {
camera.startPreview();
inPreview = true;
}
}
}
I have been trying to solve the same issue... Below code worked for me:
private void setMyPreviewSize(int width, int height) {
// Get the set dimensions
float newProportion = (float) width / (float) height;
// Get the width of the screen
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
float screenProportion = (float) screenWidth / (float) screenHeight;
// Get the SurfaceView layout parameters
android.view.ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
if (newProportion > screenProportion) {
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / newProportion );
} else {
lp.width = (int) (newProportion * (float) screenHeight);
lp.height = screenHeight;
}
// Commit the layout parameters
surfaceView.setLayoutParams(lp);
}
You can see the thread: Resizing surface view for aspect ratio change in video display in android
Here's a solution
surfaceChanged is just to get the best preview size
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.e("MYTAG", "surfaceChanged " );
Camera.Parameters myParameters = camera.getParameters();
Camera.Size myBestSize = getBestPreviewSize(width, height, myParameters);
if(myBestSize != null){
myParameters.setPreviewSize(myBestSize.width, myBestSize.height);
camera.setParameters(myParameters);
camera.startPreview();
}
}
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
imageReview.setImageBitmap(bitmap);
}
This will set the captured image on imageReview, but you need a method to get the rotation of the bitmap
you need to set imageView scaleType attribute for stretched image issue
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
/>
Related
This is my Preview class to take a picture : it's working perfectly with many devices but Android Samsung Galaxy S4 shows me bad result => the problem that the image is stretched when preview.
You can see the image below :
Here is my code :
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Camera.Size mPreviewSize;
List<Camera.Size> mSupportedPreviewSizes;
Camera mCamera;
Preview(Context context, SurfaceView sv) {
super(context);
mSurfaceView = sv;
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
try {
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
}
mCamera.setParameters(params);
}
catch (Exception e) {
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
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);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
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 surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if(mCamera != null) {
if (mPreviewSize!=null){
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}
}
}
I want to keep image support Multiscreen in android after preview.
To not have a stretched image or preview , you should choose a previewSize that keep the same ratio as the screen of the phone. Then , you should set it before launching and starting the camera. Try this code :
public void setCamera(Camera camera, int screenW, int screenH) {
//screenW ==> screen width of the phone in Pixels
//screenH ==> screen height of the phone in Pixels
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, screenW
, screenH);
}
requestLayout();
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
if (mPreviewSize != null)
params.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
List<String> focusModes = params.getSupportedFocusModes();
try {
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
} else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
}
mCamera.setParameters(params);
Log.i(TAG, " getPreviewSize " + mCamera.getParameters().getPreviewSize().width + " X "
+ mCamera.getParameters().getPreviewSize().height);
Log.i(TAG, " getPictureSize " + mCamera.getParameters().getPictureSize().width + " X "
+ mCamera.getParameters().getPictureSize().height);
} catch (Exception e) {
}
}
}
I am creating the Android app with the camera functionality.
The camera screen contains the toolbar on the top, the surfaceview (camera preview) below the toolbar, and the camera control buttons on the bottom of the screen. The screen is always in portrait.
[Some lines of the code do not related to the issue are deleted]
This is my fragment FragmentCamera
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.dmc.R;
import com.dmc.entities.Preview;
public class CameraFragment implements View.OnClickListener, View.OnTouchListener {
public static final String ARG_CAMERA_MODE = "camera.mode";
public static final String TYPE_CAMERA_MODE_IMAGE = "image";
public static final String TYPE_CAMERA_MODE_VIDEO = "video";
public MediaRecorder mrec = new MediaRecorder();
private Camera camera;
private String mCameraMode = TYPE_CAMERA_MODE_IMAGE; //or video
private com.dmc.entities.Preview preview;
private ImageView btnStopRecording;
private SurfaceView surfaceView;
private View view;
public static FrCamera getInstance(String cameraMode) {
CameraFragment fragment = new CameraFragment();
Bundle bundle = new Bundle(1);
bundle.putString(ARG_CAMERA_MODE, cameraMode);
return fragment.setArguments(bundle);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCameraMode = getArguments().getString(ARG_CAMERA_MODE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_camera, container, false);
view.setOnTouchListener(this);
btnStopRecording = (ImageView) view.findViewById(R.id.btnStopRecording);
if (!mCameraMode.equals(TYPE_CAMERA_MODE_IMAGE)) {
btnStopRecording.setOnClickListener(this);
}
surfaceView = (SurfaceView) view.findViewById(R.id.surfaceView);
view.findViewById(R.id.imgCameraTakePicture).setOnClickListener(this);
preview = new Preview(getActivity(), (SurfaceView) view.findViewById(R.id.surfaceView));
preview.setKeepScreenOn(true);
return view;
}
#Override
public void onStart() {
super.onStart();
int numCams = Camera.getNumberOfCameras();
if (numCams > 0) {
try {
camera = Camera.open(0);
preview.setCamera(camera);
camera.startPreview();
} catch (RuntimeException ex) {
}
}
}
#Override
public void onPause() {
if (camera != null) {
camera.stopPreview();
preview.setCamera(null);
camera.release();
camera = null;
}
super.onPause();
}
#Override
public void onResume() {
super.onResume();
camera.startPreview();
}
private void startVideoRecording() {
try {
mrec = new MediaRecorder();
mrec.setCamera(camera);
mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mrec.setAudioSource(MediaRecorder.AudioSource.MIC);
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
mrec.setProfile(profile);
camera.lock();
camera.unlock();
mrec.setPreviewDisplay(preview.mHolder.getSurface());
mrec.setOutputFile(outVideoFile.getPath());
mrec.setOrientationHint(Preview.rotate);
mrec.prepare();
mrec.start();
} catch (Exception ex) {
Log.e(getClass().getName(), ex.getMessage());
}
}
protected void stopRecording() {
if (mrec != null) {
mrec.stop();
mrec.release();
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.imgCameraTakenPicture:
// Save image
break;
case R.id.btnStopRecording:
stopRecording();
break;
case R.id.imgCameraTakePicture:
if (mCameraMode.equals(TYPE_CAMERA_MODE_IMAGE)) {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
} else
startVideoRecording();
break;
}
}
}
This is the Preview
import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import java.io.IOException;
import java.util.List;
public class Preview extends ViewGroup implements SurfaceHolder.Callback {
public static final float RATIO = 0.75f;
public static int rotate;
public SurfaceView mSurfaceView;
public SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
public Preview(Context context, SurfaceView sv) {
super(context);
mSurfaceView = sv;
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
params.setJpegThumbnailQuality(100);
params.setJpegQuality(100);
// Configure image format. RGB_565 is the most common format.
List<Integer> formats = params.getSupportedPictureFormats();
if (formats.contains(PixelFormat.RGB_565))
params.setPictureFormat(PixelFormat.RGB_565);
else if (formats.contains(PixelFormat.JPEG))
params.setPictureFormat(PixelFormat.JPEG);
else params.setPictureFormat(formats.get(0));
Camera.CameraInfo camInfo = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, camInfo);
int cameraRotationOffset = camInfo.orientation;
Camera.Parameters parameters = mCamera.getParameters();
int rotation = ((Activity) getContext()).getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break; // Natural orientation
case Surface.ROTATION_90:
degrees = 90;
break; // Landscape left
case Surface.ROTATION_180:
degrees = 180;
break;// Upside down
case Surface.ROTATION_270:
degrees = 270;
break;// Landscape right
}
int displayRotation;
if (camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
displayRotation = (cameraRotationOffset + degrees) % 360;
//displayRotation = (360 - displayRotation) % 360; // compensate the mirror
} else { // back-facing
displayRotation = (cameraRotationOffset - degrees + 360) % 360;
}
mCamera.setDisplayOrientation(displayRotation);
if (camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
rotate = (360 + cameraRotationOffset + degrees) % 360;
} else {
rotate = (360 + cameraRotationOffset - degrees) % 360;
}
parameters.set("orientation", "portrait");
parameters.setRotation(rotate);
mCamera.setParameters(params);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
} catch (IOException exception) {}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mHolder.getSurface() == null) {
return;
}
stopPreview();
setCamera(mCamera);
startPreview();
mCamera.startPreview();
}
public void startPreview() {
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
}
} catch (Exception e) {}
}
public void stopPreview() {
try {
if (mCamera != null)
mCamera.stopPreview();
} catch (Exception e) {}
}
}
The expected result is on the image on left side. The obtained result is on the image on the right side. The camera preview is stretched. How to fix the right aspect ratio of the camera preview?
Source code for Camera1 and Android 4-5:
#Override
protected void onResume() {
super.onResume();
camera = Camera.open(CAMERA_ID);
setPreviewSize();
}
#Override
protected void onPause() {
super.onPause();
if (camera != null)
camera.release();
camera = null;
}
...
void setPreviewSize() {
// получаем размеры экрана
Display display = getWindowManager().getDefaultDisplay();
int w1 = display.getWidth();
int h1 = display.getHeight();
boolean widthIsMax = display.getWidth() > display.getHeight();
// определяем размеры превью камеры
Camera.Size size = camera.getParameters().getPreviewSize();
RectF rectDisplay = new RectF();
RectF rectPreview = new RectF();
// RectF экрана, соотвествует размерам экрана
rectDisplay.set(0, 0, w1, h1);
// подготовка матрицы преобразования
Matrix matrix = new Matrix();
// RectF первью
if (widthIsMax) {
// превью в горизонтальной ориентации
rectPreview.set(0, 0, size.width, size.height);
// если экран будет "втиснут" в превью (третий вариант из урока)
matrix.setRectToRect(rectPreview, rectDisplay,
Matrix.ScaleToFit.START);
} else {
// превью в вертикальной ориентации
rectPreview.set(0, 0, size.height, size.width);
// если превью будет "втиснут" в экран (второй вариант из урока)
matrix.setRectToRect(rectPreview, rectDisplay,
Matrix.ScaleToFit.START);
}
// преобразование
matrix.mapRect(rectPreview);
// установка размеров surface из получившегося преобразования
h0 = (int) (rectPreview.bottom);
w0 = (int) (rectPreview.right);
surfaceView.getLayoutParams().height = h0;
surfaceView.getLayoutParams().width = w0;
}
See http://startandroid.ru/ru/uroki/vse-uroki-spiskom/264-urok-132-kamera-vyvod-izobrazhenija-na-ekran-obrabotka-povorota.html
Below is the solution of Camera Preview Stretched
It's worked on making my custom camera activity
I set the framelayout which holds the surface view that displays the camera's parameters.
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
mCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for(Camera.Size str: mSupportedPreviewSizes)
Log.e(TAG, str.width + "/" + str.height);
// 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);
}
public void surfaceCreated(SurfaceHolder holder) {
// empty. surfaceChanged will take care of stuff
}
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) {
Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + 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 {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
#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);
}
if (mPreviewSize!=null) {
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;
}
}
Reference link:
Android Camera Preview Stretched
I am using ZBarScannerActivity in my android app. but I am getting a small surface view on device. Actually I want full Screen camera preview to scan the QR code.
Any help would be appreciated.
Thank you.
here is the code of ZbarScanner Activity
package com.dm.zbar.android.scanner;
public class ZBarScannerActivity extends Activity implements Camera.PreviewCallback, ZBarConstants {
private static final String TAG = "ZBarScannerActivity";
private CameraPreview mPreview;
private Camera mCamera;
private ImageScanner mScanner;
private Handler mAutoFocusHandler;
private boolean mPreviewing = true;
static {
System.loadLibrary("iconv");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!isCameraAvailable()) {
// Cancel request if there is no rear-facing camera.
cancelRequest();
return;
}
// Hide the window title.
//requestWindowFeature(Window.FEATURE_NO_TITLE);
//getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
mAutoFocusHandler = new Handler();
// Create and configure the ImageScanner;
setupScanner();
// Create a RelativeLayout container that will hold a SurfaceView,
// and set it as the content of our activity.
mPreview = new CameraPreview(this, this, autoFocusCB);
setContentView(mPreview);
}
public void setupScanner() {
mScanner = new ImageScanner();
mScanner.setConfig(0, Config.X_DENSITY, 3);
mScanner.setConfig(0, Config.Y_DENSITY, 3);
int[] symbols = getIntent().getIntArrayExtra(SCAN_MODES);
if (symbols != null) {
mScanner.setConfig(Symbol.NONE, Config.ENABLE, 0);
for (int symbol : symbols) {
mScanner.setConfig(symbol, Config.ENABLE, 1);
}
}
}
#Override
protected void onResume() {
super.onResume();
// Open the default i.e. the first rear facing camera.
mCamera = Camera.open();
if(mCamera == null) {
// Cancel request if mCamera is null.
cancelRequest();
return;
}
mPreview.setCamera(mCamera);
mPreview.showSurfaceView();
mPreviewing = true;
}
#Override
protected void onPause() {
super.onPause();
// Because the Camera object is a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera != null) {
mPreview.setCamera(null);
mCamera.cancelAutoFocus();
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
// According to Jason Kuang on http://stackoverflow.com/questions/6519120/how-to-recover-camera-preview-from-sleep,
// there might be surface recreation problems when the device goes to sleep. So lets just hide it and
// recreate on resume
mPreview.hideSurfaceView();
mPreviewing = false;
mCamera = null;
}
}
public boolean isCameraAvailable() {
PackageManager pm = getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
public void cancelRequest() {
Intent dataIntent = new Intent();
dataIntent.putExtra(ERROR_INFO, "Camera unavailable.");
setResult(Activity.RESULT_CANCELED, dataIntent);
finish();
}
public void onPreviewFrame(byte[] data, Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
Image barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
int result = mScanner.scanImage(barcode);
if (result != 0) {
mCamera.cancelAutoFocus();
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mPreviewing = false;
SymbolSet syms = mScanner.getResults();
for (Symbol sym : syms) {
String symData = sym.getData();
if (!TextUtils.isEmpty(symData)) {
Intent dataIntent = new Intent();
dataIntent.putExtra(SCAN_RESULT, symData);
dataIntent.putExtra(SCAN_RESULT_TYPE, sym.getType());
setResult(Activity.RESULT_OK, dataIntent);
finish();
break;
}
}
}
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if(mCamera != null && mPreviewing) {
mCamera.autoFocus(autoFocusCB);
}
}
};
// Mimic continuous auto-focusing
Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
and CameraPreview Class
class CameraPreview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "CameraPreview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
PreviewCallback mPreviewCallback;
AutoFocusCallback mAutoFocusCallback;
CameraPreview(Context context, PreviewCallback previewCallback, AutoFocusCallback autoFocusCb) {
super(context);
mPreviewCallback = previewCallback;
mAutoFocusCallback = autoFocusCb;
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
//Changes********
mCamera.setDisplayOrientation(90);
mCamera.getParameters().getMaxNumFocusAreas();
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void hideSurfaceView() {
mSurfaceView.setVisibility(View.INVISIBLE);
}
public void showSurfaceView() {
mSurfaceView.setVisibility(View.VISIBLE);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.cancelAutoFocus();
mCamera.stopPreview();
}
}
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;
// Try to find an size match aspect ratio and size
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);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
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;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (holder.getSurface() == null){
// preview surface does not exist
return;
}
if (mCamera != null) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
// mCamera.setDisplayOrientation(90);
mCamera.setParameters(parameters);
mCamera.setPreviewCallback(mPreviewCallback);
mCamera.startPreview();
mCamera.autoFocus(mAutoFocusCallback);
}
}
}
Please help me getting the scenario of Camera Preview size.
I am getting a small surface view on device. Actually I want full Screen camera preview to scan the QR code
If you are saying that camera isn't occupying the entire screen then try to change the
android:layout_width="match_parent"
android:layout_height="match_parent"
of SurfaceView and parent_layout
If it is about the scan area that you want to be in full screen, here it goes:
mScannerView = new ZBarScannerView(this) {
/**
* this will alter the scanning area
**/
#Override
protected IViewFinder createViewFinderView(Context context) {
return new CustomViewFinderView(context);
}
};
private class CustomViewFinderView extends ViewFinderView {
Context context;
public CustomViewFinderView(Context context) {
super(context);
this.context = context;
setLaserEnabled(true);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (getFramingRect() != null) {
updateFrameRect();
setBorderColor(ContextCompat.getColor(context, R.color.colorPrimary));
}
}
private void updateFrameRect() {
Point viewResolution = new Point(this.getWidth(), this.getHeight());
int height = (int) ((float) this.getHeight());
int width = (int) ((float) this.getWidth());
int leftOffset = (viewResolution.x - width) / 2;
int topOffset = (viewResolution.y - height) / 2;
getFramingRect().left = leftOffset;
getFramingRect().top = topOffset;
getFramingRect().right = leftOffset + width;
getFramingRect().bottom = topOffset + height;
}
}
Result:
I have solved this by removing following code from Camerapreview Class
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
it worked for me.
It will give you full screen camera.
Thank you.
I am using custom camera but the preview of custom camera is stretched and blur but after the click picture image shows right. Please help me how i can set the preview right on every device , thats my code
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
public static SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
Preview(Context context, SurfaceView sv) {
super(context);
mSurfaceView = sv;
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a wrapper to a SurfaceView that
// centers the camera preview instead of stretching it.
int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
// we only allow landscape, if height > width - it means that we are in rotation animation. Swap width with height
if (height > width) {
width += height;
height = width - height;
width = width - height;
}
setMeasuredDimension(width, height);
Log.v("Camera", width + "x" + height);
if (mSupportedPreviewSizes == null && mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
}
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
private Size getOptimalPreviewSize(List<Camera.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;
// Try to find an size match aspect ratio and size
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);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
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;
}
public void refreshCamera(Camera camera) {
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
setCamera(camera);
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
try {
Camera.Parameters parameters = mCamera.getParameters();
// List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
//Camera.Size previewSize = previewSizes.get(4); //480h x 720w
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
}
after click image shows right
I want to stream the camera preview of the android camera, onto a view. The intention is to afterwards add various things to the view, using onDraw(). I don't need to actually capture the image at any time.
It doesn't have to be in the highest quality or largest number of frames per second.
Does anyone have an idea how this can be done?
add this to your xml:
<SurfaceView
android:id="#+id/camerapreview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
into your activity-class:
private Preview mPreview;
Camera mCamera;
int numberOfCameras;
int cameraCurrentlyLocked;
int defaultCameraId;
onCreate-Method:
mPreview = new Preview(this);
setContentView(mPreview);
mPreview.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mCamera.autoFocus(null);
}
});
#Override
protected void onPause() {
super.onPause();
// Because the Camera object is a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera != null) {
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}
}
#Override
protected void onResume() {
super.onResume();
// Open the default i.e. the first rear facing camera.
mCamera = Camera.open();
cameraCurrentlyLocked = defaultCameraId;
mPreview.setCamera(mCamera);
}
and the preview-class:
public class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
public Preview(Context context) {
super(context);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
}
}
public void switchCamera(Camera camera) {
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
camera.setParameters(parameters);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
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;
// Try to find an size match aspect ratio and size
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);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
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;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
if(mCamera != null){
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}
}