Android camera preview look strange - android

I am implementing a camera app and when I look at the preview (especially with front camera), the image is very fat. It looks like the image get stretched horizontally. I follow the sdk sample with the optimzed camera size but it doesn't help. How can I adjust my camera setting so that it will preview like the other camera app?
Thanks.
My code is below.
public class CameraActivity extends Activity implements SurfaceHolder.Callback, Camera.ShutterCallback, Camera.PictureCallback {
Camera m_camera;
SurfaceView m_surfaceView;
int m_numOfCamera;
int m_defaultCameraId;
int m_currentCamera;
int m_surfaceWidth;
int m_surfaceHeight;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
getActionBar().setDisplayHomeAsUpEnabled(true);
m_surfaceView = (SurfaceView)findViewById(R.id.cameraPreview);
m_surfaceView.getHolder().addCallback(this);
m_camera = Camera.open();
m_numOfCamera = Camera.getNumberOfCameras();
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < m_numOfCamera; ++i) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
m_defaultCameraId = i;
m_currentCamera = m_defaultCameraId;
}
}
if (m_numOfCamera < 1) {
MenuItem switchCam = (MenuItem)findViewById(R.id.menu_switch_camera);
switchCam.setVisible(false);
}
}
#Override
public void onPause() {
super.onPause();
m_camera.stopPreview();
}
#Override
public void onDestroy() {
super.onDestroy();
m_camera.release();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_camera, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(final MenuItem item)
{
if (item.getItemId() == android.R.id.home)
{
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
}
else if (item.getItemId() == R.id.menu_switch_camera)
{
if (m_camera != null) {
m_camera.stopPreview();
m_camera.release();
m_camera = null;
}
m_camera = Camera.open((m_currentCamera + 1) % m_numOfCamera);
m_currentCamera = (m_currentCamera + 1) % m_numOfCamera;
Camera.Parameters params = m_camera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size size = getOptimalPreviewSize(sizes, m_surfaceWidth, m_surfaceHeight);
params.setPreviewSize(size.width, size.height);
m_camera.setParameters(params);
setCameraDisplayOrientation(this, m_currentCamera, m_camera);
m_camera.startPreview();
try {
m_camera.setPreviewDisplay(m_surfaceView.getHolder());
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
return true;
}
public void onPictureTaken(byte[] arg0, Camera arg1) {
// TODO Auto-generated method stub
}
public void onShutter() {
// TODO Auto-generated method stub
}
public void surfaceChanged(SurfaceHolder arg0, int format, int w, int h) {
m_surfaceWidth = w;
m_surfaceHeight = h;
Camera.Parameters params = m_camera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size selected = getOptimalPreviewSize(sizes, w, h);
params.setPreviewSize(selected.width, selected.height);
m_camera.setParameters(params);
setCameraDisplayOrientation(this, m_currentCamera, m_camera);
m_camera.startPreview();
}
private static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
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.setDisplayOrientation(result);
}
public void surfaceCreated(SurfaceHolder arg0) {
try {
m_camera.setPreviewDisplay(m_surfaceView.getHolder());
} catch (Exception e) {
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
}
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;
}
}

The camera preview always fills up the SurfaceView showing it. If the aspect ratio of m_surfaceView doesn't match with the camera's aspect ratio, the preview will be stretched.
You'll need to create m_surfaceView matching the aspect ratio. That means, you'll need to create it from code, not from layout XML file.
There is a sample project APIDemos that you'll find in android sample projects. In the project there is a thing named CameraPreview. This one has a good demonstration for setting up camera preview in a SurfaceView. It has a class that extends ViewGroup, and adds the SurfaceView as its child from the code. The onMeasure() method has been overridden to determine the height and width of the SurfaceView, so the aspect ratio is preserved. Take a look on the project, and I hope it will be clear.
[Sorry I couldn't post the link here - this is supposed to be the link, but I found it broken. But if you have installed the sample projects with the Android SDK, you can find the project in the samples. Open a new Android Sample Project, select APIDemos, then look for a class named CameraPreview. It should be in the package com.example.android.apis.graphics, as far as I remember.]

I changed onLayout method and not camera preview is not stretched. Rest of the thing are same like APiDemo which find here sdk/sample/adroid-18.The idea is we have only some supported size of preview but our view size may not always match with preview size. so i took larger preview size then my imageview size. it works for me. May help someone..
#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;
left = (width - scaledChildWidth) / 2;
top = 0;
right = (width + scaledChildWidth) / 2;
bottom = height;
child.layout(left, top, right, bottom);
} else {
final int scaledChildHeight = previewHeight * width
/ previewWidth;
left = 0;
top = (height - scaledChildHeight) / 2;
right = width;
bottom = (height + scaledChildHeight) / 2;
child.layout(left, top, right, bottom);
}
}
}

I have problem with too stretching camera preview.
It is too stretching at vertical and landscape mode.
So at manifest i added screenOrentation="Portrait",
but it did not help,still preview is rescaled at
any position (vertical - preview is to wide or
landscape is too long) you can
see this at screens.
I would like to add at Samsung ace III everything is fine but at LG Nexus 4 is stretching
package pl.probs.camera.component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import pl.probs.lib.debug.L;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private static boolean showLogs = true;
private SurfaceHolder mHolder;
private Camera mCamera;
private Context context;
private Parameters resolution;
private List<Size> lSuportedPreviewSize;
private static int cOrientation = 0; // aktualny kat orientacji
private static boolean cOrientationChanged = false; // Stan orientacji
// zostal zmieniony
// wzgledem poprzedniego
private Display display; // Rozmiar ekranu
private Point displaySize; // Zmienna przechowuje Rozmiar Ekranu
private Point optimalPreviewSize;
public CameraPreview(Context context, Camera camera, int resolution) {
super(context);
this.optimalPreviewSize = new Point();
this.context = context;
this.mCamera = camera;
setDisplaySize(this.display);
setFocusable(true);
setFocusableInTouchMode(true);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
this.resolution = getMinResolution(resolution);
this.optimalPreviewSize = getOptimalPreviewResolution(this.display);
Size s = mCamera.getParameters().getPreviewSize(); // Sprawdzenie jaki
// prewiev ustawiony
}
public Point getOptimalPreviewSize() {
return optimalPreviewSize;
}
public void surfaceCreated(SurfaceHolder holder) {
try {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewDisplay(holder);
Size s = mCamera.getParameters().getPreviewSize();
mCamera.startPreview();
}
} catch (IOException e) {
L.d("Błąd ustawiania podglÄ…du: " + e.getMessage());
}
}
protected void onPause() {
// Because the Camera object is a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null) {
mCamera.stopPreview();
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters setPrevOrientation = mCamera.getParameters();
if (mHolder.getSurface() == null)
return;
try {
mCamera.stopPreview();
Size sizeBefore = mCamera.getParameters().getPreviewSize();
setPrevOrientation.setRotation(setCameraDisplayOrientation((Activity) context, getCameraId(), mCamera));
// Orientacja Portrait np 640x480 Landscape 480x640
this.resolution.setPreviewSize(this.optimalPreviewSize.x, this.optimalPreviewSize.y);
mCamera.setParameters(this.resolution);
Size sizeAfter = mCamera.getParameters().getPreviewSize();
} catch (RuntimeException e) {
L.d("Podgląd nie istnieje");
}
try {
mCamera.stopPreview();
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
L.d("błąd podgladu: " + e.getMessage());
}
}
#SuppressLint("ClickableViewAccessibility")
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mCamera.autoFocus(new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
// do something
}
});
}
return true;
}
private static int setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
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;
}
cOrientation = degrees;
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.setDisplayOrientation(result);
return result;
}
private int getCameraId() {
int cameraId = -1;
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == CameraInfo.CAMERA_FACING_BACK) {
cameraId = i;
break;
}
}
return cameraId;
}
private Parameters getMinResolution(int desireResolutionInMpx) {
int height[], width[], size;
float megapixels;
Camera.Parameters p = mCamera.getParameters();
size = p.getSupportedPictureSizes().size();
height = new int[size];
width = new int[size];
for (int i = 0; i < size; i++) {
height[i] = p.getSupportedPictureSizes().get(i).height;
width[i] = p.getSupportedPictureSizes().get(i).width;
megapixels = (float) (((float) height[i] * (float) width[i]) / 1024000);
if (megapixels <= desireResolutionInMpx) {
p.setPictureSize(width[i], height[i]);
break;
}
}
return p;
}
private Point getOptimalPreviewResolution(Display displaySize) {
lSuportedPreviewSize = mCamera.getParameters().getSupportedPreviewSizes();
Point optimalPreviewSize = new Point();
int displayWidth = displaySize.getWidth(); // szerokosc ekranu
int displayHeight = displaySize.getHeight(); // wysokosc ekranu
int cameraHeight; // wspierana wysokosc kamery
int cameraWidth; // wspierana szerokosc kamery
// Lista przechowywujace SupportedPreviewSize kamery, wszyskie
// rozdzielczosci mniejsze od szerokosc i wysokosci ekranu
List<Point> lOptimalPoint = new ArrayList<Point>();
// Pomocniczo do listowania zawartosci listy
// TODO manta displayHeight cameraHeight brak oraz width brak zgodnosci
// (
System.out.println(lOptimalPoint.toString());
for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
Log.i(TAG, "w " + lSuportedPreviewSize.get(i).width + " h " + lSuportedPreviewSize.get(i).height + " \n");
}
// Wyszukanie wszystkich wysokosci kamery mniejszej od wysokosci ekranu
for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
// TODO Uwazaj kamera zapisuje swoj rozmiar dla pozycji landscape
// gdzie height = 480 a width = 800
cameraHeight = lSuportedPreviewSize.get(i).width;
cameraWidth = lSuportedPreviewSize.get(i).height;
// Porownaj wysokosc ekranu urzadzenia z wysokosci supportedPreview
// dodaj do listy
if (displayHeight > cameraHeight) {
lOptimalPoint.add(new Point(cameraHeight, cameraWidth));
}
}
// Sortowanie rosnaco
Collections.sort(lOptimalPoint, new ComapreSupportedPreviewByWidth());
// Ostatni element listy optymalny
optimalPreviewSize = lOptimalPoint.get(lOptimalPoint.size()-1);
// Zwracana rozdzielczosc landscape aparatu np (800x600)
return optimalPreviewSize;
}
private void setDisplaySize(Display display) {
Activity activity = (Activity) this.context; // Pobierz aktywnosc aby
// znać rozmiar ekranu
this.display = activity.getWindowManager().getDefaultDisplay();
}
class ComapreSupportedPreviewByWidth implements Comparator<Point> {
#Override
public int compare(Point lhs, Point rhs) {
return lhs.x - rhs.x;
}
}
}
Link to screens and project doing at eclipse

I already solved problem. What could cause problem with strange camera preview.
Status bar takes spaces - you can hide it Hiding the Status Bar
Some spaces also take TitleBar - you can turn off this at manifest
android:theme="#android:style/Theme.NoTitleBar">
Changed activity orientation to landscape "beacuse camera preview support that orientation" - you can check this at API demo Graphics->CameraPreview
algorithm that compares the size of Display.getWidth () Camera.getParameters size (). getSupportedPreviewSizes (); if they are the same is a function of surfaceChanged change Parametrs.setPreviewSize (x, y) you received when searching the list
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters setPrevOrientation = mCamera.getParameters();
if (mHolder.getSurface() == null)
return;
try {
mCamera.stopPreview();
Size sizeBefore = mCamera.getParameters().getPreviewSize();
setPrevOrientation.setRotation(setCameraDisplayOrientation(
(Activity) context, getCameraId(), mCamera));
// Orientacja Portrait np 640x480 Landscape 480x640
this.resolution.setPreviewSize(this.optimalPreviewSize.x,
this.optimalPreviewSize.y);
mCamera.setParameters(this.resolution);
Size sizeAfter = mCamera.getParameters().getPreviewSize();
} catch (RuntimeException e) {
L.d("Podgląd nie istnieje");
}
try {
mCamera.stopPreview();
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
L.d("błąd podgladu: " + e.getMessage());
}
}
private Point getOptimalPreviewResolution(Display displaySize) {
lSuportedPreviewSize = mCamera.getParameters()
.getSupportedPreviewSizes();
Point optimalPreviewSize = new Point();
int displayWidth = displaySize.getWidth();
int displayHeight = displaySize.getHeight();
int cameraHeight;
int cameraWidth;
List<Point> lOptimalPoint = new ArrayList<Point>();
for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
cameraHeight = lSuportedPreviewSize.get(i).width;
cameraWidth = lSuportedPreviewSize.get(i).height;
if (displayHeight >= cameraHeight) {
lOptimalPoint.add(new Point(cameraHeight, cameraWidth));
}
}
// Sort ascending
Collections.sort(lOptimalPoint,
new ComapreSupportedPreviewByWidth());
// Last element is optimal
optimalPreviewSize = lOptimalPoint.get(lOptimalPoint.size() - 1);
// Return resolution - camera at landscape mode (800x600)
return optimalPreviewSize;
}
class ComapreSupportedPreviewByWidth implements Comparator<Point> {
#Override
public int compare(Point lhs, Point rhs) {
return lhs.x - rhs.x;
}

Related

How to fix the right aspect ratio of the camera preview (surfaceview) in Android?

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

Camera is inverted in Nexus device

I am trying to create custom camera preview logic that actually works properly, for all scenarios:
any device: phone, tablet
any camera: front-facing, rear-facing
android.hardware.Camera
My android:minSdkVersion is 14 and android:targetSdkVersion is 21.
I have implemented custom camera preview class to set display orientation for camera preview and working very well for all devices without only Nexus devices. Nexus devices have I think default 180 orientation.
While I am starting my camera in Nexus devices it is showing inverted. To overcome with i have checked with Build.MANUFACTURER & Build.MODEL to identify the device and set orientation according to it.
if (Build.MODEL.equals("Nexus 6P") && Build.MANUFACTURER.equals("Huawei")) mCamera.setDisplayOrientation(90);
else mCamera.setDisplayOrientation(270);
But it is not working. So can anyone have idea to overcome with this and recommended way !! Advance help would be appreciated !!
As far as I know this problem doesn't occur on Nexus 5. I had to deal with it on a Nexus 5X and I lost some time trying(Click here to see why). As a big note, I can't guarantee that it's the best solution, but it fixed all the problems I had. To solve it I did something like this:
I created a class CameraPreview extends SurfaceView only to encapsulate all the preview initialisation in one place. Here is the constructor for that class:
public CameraPreview(Context context, int screenRotation, Camera camera) {
super(context);
mCamera = camera;
mScreenRotation = screenRotation;
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
}
To create the preview I used this: mPreview = new CameraPreview(getContext(), screenRotation, mCamera);, where screenRotation is int screenRotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
When the surfaceCreated callback is called:
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
setCameraDisplayOrientation(mScreenRotation, 0, mCamera);
Here,0 comes from the cameraId (it might be different if you're using the front facing camera). And here is all the magic:
public void setCameraDisplayOrientation(int screenRotation, int cameraId, Camera camera) {
int rotation = getRotationAngle(screenRotation, cameraId);
camera.setDisplayOrientation(rotation);
}
public static int getRotationAngle(int screenRotation, int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int degrees = 0;
switch (screenRotation) {
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;
}
return result;
}
I hope that this will fix the problem, but before starting to write it, make sure that you read the link I provided to see why the problem takes place. Hope this will fix it for you too.
To initiate in activity :
CameraPreviewNew mPreview = new ResizableCameraPreview(this, cameraId, CameraPreviewNew.LayoutMode.NoBlank, false, screenHeight, screenWidth); // cameraId for front or rear
LinearLayout.LayoutParams previewLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
frameCamera.addView(mPreview, 0, previewLayoutParams);
CameraPreviewNew.java
public class CameraPreviewNew extends SurfaceView implements SurfaceHolder.Callback {
private static boolean DEBUGGING = false;
private static final String LOG_TAG = "CameraPreviewSample";
private static final String CAMERA_PARAM_ORIENTATION = "orientation";
private static final String CAMERA_PARAM_LANDSCAPE = "landscape";
private static final String CAMERA_PARAM_PORTRAIT = "portrait";
protected Activity mActivity;
private SurfaceHolder mHolder;
protected Camera mCamera;
protected List<Camera.Size> mPreviewSizeList;
protected List<Camera.Size> mPictureSizeList;
protected Camera.Size mPreviewSize;
protected Camera.Size mPictureSize;
private int mSurfaceChangedCallDepth = 0;
private int mCameraId;
private LayoutMode mLayoutMode;
private int mCenterPosX = -1;
private int mCenterPosY;
private int screenHeight, screenWidth;
PreviewReadyCallback mPreviewReadyCallback = null;
public enum LayoutMode {
FitToParent, // Scale to the size that no side is larger than the parent
NoBlank // Scale to the size that no side is smaller than the parent
}
public interface PreviewReadyCallback {
void onPreviewReady();
}
/**
* State flag: true when surface's layout size is set and surfaceChanged()
* process has not been completed.
*/
protected boolean mSurfaceConfiguring = false;
public CameraPreviewNew(Activity activity, int cameraId, LayoutMode mode, int screenHeight, int screenWidth) {
super(activity); // Always necessary
mActivity = activity;
mLayoutMode = mode;
this.screenHeight = screenHeight;
this.screenWidth = screenWidth;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// mHolder.setFixedSize(fixWidth, fixHeight);
// FileLog.v("Camera ID ::::::::::: " + cameraId);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
if (Camera.getNumberOfCameras() > cameraId) {
mCameraId = cameraId;
} else {
mCameraId = 0;
}
} else {
mCameraId = 0;
}
// FileLog.d("Camera ID ::::::::::: " + cameraId);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
mCamera = Camera.open(mCameraId);
} else {
mCamera = Camera.open();
}
Camera.Parameters cameraParams = mCamera.getParameters();
mPreviewSizeList = cameraParams.getSupportedPreviewSizes();
mPictureSizeList = cameraParams.getSupportedPictureSizes();
// FileLog.d("Preview Size ID ::::::::::: " + mPreviewSizeList);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
mCamera.release();
mCamera = null;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mSurfaceChangedCallDepth++;
doSurfaceChanged(width, height);
mSurfaceChangedCallDepth--;
}
public void doSurfaceChanged(int width, int height) {
mCamera.stopPreview();
Camera.Parameters cameraParams = mCamera.getParameters();
boolean portrait = isPortrait();
// The code in this if-statement is prevented from executed again when surfaceChanged is
// called again due to the change of the layout size in this if-statement.
if (!mSurfaceConfiguring) {
Camera.Size previewSize = determinePreviewSize(portrait, width, height);
Camera.Size pictureSize = determinePictureSize(previewSize);
if (DEBUGGING) { Log.v(LOG_TAG, "Desired Preview Size - w: " + width + ", h: " + height); }
mPreviewSize = previewSize;
mPictureSize = pictureSize;
mSurfaceConfiguring = adjustSurfaceLayoutSize(previewSize, portrait, width, height);
// Continue executing this method if this method is called recursively.
// Recursive call of surfaceChanged is very special case, which is a path from
// the catch clause at the end of this method.
// The later part of this method should be executed as well in the recursive
// invocation of this method, because the layout change made in this recursive
// call will not trigger another invocation of this method.
if (mSurfaceConfiguring && (mSurfaceChangedCallDepth <= 1)) {
return;
}
}
configureCameraParameters(cameraParams, portrait);
mSurfaceConfiguring = false;
try {
mCamera.startPreview();
} catch (Exception e) {
Log.w(LOG_TAG, "Failed to start preview: " + e.getMessage());
// Remove failed size
mPreviewSizeList.remove(mPreviewSize);
mPreviewSize = null;
// Reconfigure
if (mPreviewSizeList.size() > 0) { // prevent infinite loop
surfaceChanged(null, 0, width, height);
} else {
Log.w(LOG_TAG, "Gave up starting preview");
}
}
if (null != mPreviewReadyCallback) {
mPreviewReadyCallback.onPreviewReady();
}
}
/**
* #param portrait
* #param reqWidth must be the value of the parameter passed in surfaceChanged
* #param reqHeight must be the value of the parameter passed in surfaceChanged
* #return Camera.Size object that is an element of the list returned from Camera.Parameters.getSupportedPreviewSizes.
*/
protected Camera.Size determinePreviewSize(boolean portrait, int reqWidth, int reqHeight) {
// Meaning of width and height is switched for preview when portrait,
// while it is the same as user's view for surface and metrics.
// That is, width must always be larger than height for setPreviewSize.
int reqPreviewWidth; // requested width in terms of camera hardware
int reqPreviewHeight; // requested height in terms of camera hardware
if (portrait) {
reqPreviewWidth = reqHeight;
reqPreviewHeight = reqWidth;
} else {
reqPreviewWidth = reqWidth;
reqPreviewHeight = reqHeight;
}
if (DEBUGGING) {
Log.v(LOG_TAG, "Listing all supported preview sizes");
for (Camera.Size size : mPreviewSizeList) {
Log.v(LOG_TAG, " w: " + size.width + ", h: " + size.height);
}
Log.v(LOG_TAG, "Listing all supported picture sizes");
for (Camera.Size size : mPictureSizeList) {
Log.v(LOG_TAG, " w: " + size.width + ", h: " + size.height);
}
}
// Adjust surface size with the closest aspect-ratio
float reqRatio = ((float) reqPreviewWidth) / reqPreviewHeight;
float curRatio, deltaRatio;
float deltaRatioMin = Float.MAX_VALUE;
Camera.Size retSize = null;
for (Camera.Size size : mPreviewSizeList) {
curRatio = ((float) size.width) / size.height;
deltaRatio = Math.abs(reqRatio - curRatio);
if (deltaRatio < deltaRatioMin) {
deltaRatioMin = deltaRatio;
retSize = size;
}
}
retSize = mPreviewSizeList.get(0);
return retSize;
}
protected Camera.Size determinePictureSize(Camera.Size previewSize) {
Camera.Size retSize = null;
for (Camera.Size size : mPictureSizeList) {
if (size.equals(previewSize)) {
return size;
}
}
if (DEBUGGING) { Log.v(LOG_TAG, "Same picture size not found."); }
// if the preview size is not supported as a picture size
float reqRatio = ((float) previewSize.width) / previewSize.height;
float curRatio, deltaRatio;
float deltaRatioMin = Float.MAX_VALUE;
for (Camera.Size size : mPictureSizeList) {
curRatio = ((float) size.width) / size.height;
deltaRatio = Math.abs(reqRatio - curRatio);
if (deltaRatio < deltaRatioMin) {
deltaRatioMin = deltaRatio;
retSize = size;
}
}
retSize = mPictureSizeList.get(0);
return retSize;
}
protected boolean adjustSurfaceLayoutSize(Camera.Size previewSize, boolean portrait,
int availableWidth, int availableHeight) {
float tmpLayoutHeight, tmpLayoutWidth;
if (portrait) {
tmpLayoutHeight = previewSize.width;
tmpLayoutWidth = previewSize.height;
} else {
tmpLayoutHeight = previewSize.height;
tmpLayoutWidth = previewSize.width;
}
float factH, factW, fact;
factH = availableHeight / tmpLayoutHeight;
factW = availableWidth / tmpLayoutWidth;
if (mLayoutMode == LayoutMode.FitToParent) {
// Select smaller factor, because the surface cannot be set to the size larger than display metrics.
if (factH < factW) {
fact = factH;
} else {
fact = factW;
}
} else {
if (factH < factW) {
fact = factW;
} else {
fact = factH;
}
}
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)this.getLayoutParams();
int layoutHeight = (int) (tmpLayoutHeight * fact);
int layoutWidth = (int) (tmpLayoutWidth * fact);
if (DEBUGGING) {
Log.v(LOG_TAG, "Preview Layout Size - w: " + layoutWidth + ", h: " + layoutHeight);
Log.v(LOG_TAG, "Scale factor: " + fact);
}
boolean layoutChanged;
if ((layoutWidth != this.getWidth()) || (layoutHeight != this.getHeight())) {
int diffHeight = (screenHeight - layoutHeight) / 2;
layoutParams.height = layoutHeight + diffHeight;
int diffWidth = (screenWidth - layoutWidth) / 2;
layoutParams.width = layoutWidth + diffWidth;
if (mCenterPosX >= 0) {
layoutParams.topMargin = mCenterPosY - (layoutHeight / 2);
layoutParams.leftMargin = mCenterPosX - (layoutWidth / 2);
}
this.setLayoutParams(layoutParams); // this will trigger another surfaceChanged invocation.
layoutChanged = true;
} else {
layoutChanged = false;
}
return layoutChanged;
}
/**
* #param x X coordinate of center position on the screen. Set to negative value to unset.
* #param y Y coordinate of center position on the screen.
*/
public void setCenterPosition(int x, int y) {
mCenterPosX = x;
mCenterPosY = y;
}
protected void configureCameraParameters(Camera.Parameters cameraParams, boolean portrait) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { // for 2.1 and before
if (portrait) {
cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_PORTRAIT);
} else {
cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_LANDSCAPE);
}
} else { // for 2.2 and later
int angle;
Display display = mActivity.getWindowManager().getDefaultDisplay();
switch (display.getRotation()) {
case Surface.ROTATION_0: // This is display orientation
angle = 90; // This is camera orientation
break;
case Surface.ROTATION_90:
angle = 0;
break;
case Surface.ROTATION_180:
angle = 270;
break;
case Surface.ROTATION_270:
angle = 180;
break;
default:
angle = 90;
break;
}
Log.v(LOG_TAG, "angle: " + angle);
mCamera.setDisplayOrientation(angle);
}
cameraParams.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
cameraParams.setPictureSize(mPictureSize.width, mPictureSize.height);
cameraParams.setZoom(0);
// if (cameraParams.isZoomSupported()) {
final int maxZoomLevel = cameraParams.getMaxZoom();
Log.e("max ZOOM ", "is " + maxZoomLevel);
// }
// cameraParams.setPreviewSize(fixWidth, fixHeight);
// cameraParams.setPictureSize(fixWidth, fixHeight);
if (DEBUGGING) {
Log.v(LOG_TAG, "Preview Actual Size - w: " + mPreviewSize.width + ", h: " + mPreviewSize.height);
Log.v(LOG_TAG, "Picture Actual Size - w: " + mPictureSize.width + ", h: " + mPictureSize.height);
}
mCamera.setParameters(cameraParams);
}
#SuppressWarnings("unused")
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.2;
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) {
Log.d("Camera", "Checking size " + size.width + "w " + size.height
+ "h");
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 surfaceDestroyed(SurfaceHolder holder) {
stop();
}
public void stop() {
try {
if (null == mCamera) {
return;
}
if(mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}catch (Exception e){
e.printStackTrace();
}
}
public boolean isPortrait() {
return (mActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
}
public void setOneShotPreviewCallback(PreviewCallback callback) {
if (null == mCamera) {
return;
}
mCamera.setOneShotPreviewCallback(callback);
}
public void setPreviewCallback(PreviewCallback callback) {
if (null == mCamera) {
return;
}
mCamera.setPreviewCallback(callback);
}
public Camera.Size getPreviewSize() {
return mPreviewSize;
}
public void setOnPreviewReady(PreviewReadyCallback cb) {
mPreviewReadyCallback = cb;
}
public Camera getPreviewCamera() {
return mCamera;
}
}
ResizableCameraPreview.java
public class ResizableCameraPreview extends CameraPreviewNew {
private static boolean DEBUGGING = false;
private static final String LOG_TAG = "ResizableCameraPreviewSample";
/**
* #param activity
* #param addReversedSizes is set to true to add reversed values of supported preview-sizes to the list.
*/
public ResizableCameraPreview(Activity activity, int cameraId, LayoutMode mode, boolean addReversedSizes, int screenHeight, int screenWidth) {
super(activity, cameraId, mode, screenHeight, screenWidth);
if (addReversedSizes) {
List<Camera.Size> sizes = mPreviewSizeList;
int length = sizes.size();
for (int i = 0; i < length; i++) {
Camera.Size size = sizes.get(i);
Camera.Size revSize = mCamera.new Size(size.height, size.width);
sizes.add(revSize);
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mCamera.stopPreview();
Camera.Parameters cameraParams = mCamera.getParameters();
boolean portrait = isPortrait();
if (!mSurfaceConfiguring) {
Camera.Size previewSize = determinePreviewSize(portrait, width, height);
Camera.Size pictureSize = determinePictureSize(previewSize);
Log.v(LOG_TAG, "Desired Preview Size - w: " + width + ", h: " + height);
mPreviewSize = previewSize;
mPictureSize = pictureSize;
mSurfaceConfiguring = adjustSurfaceLayoutSize(previewSize, portrait, width, height);
if (mSurfaceConfiguring) {
return;
}
}
configureCameraParameters(cameraParams, portrait);
mSurfaceConfiguring = false;
try {
mCamera.startPreview();
} catch (Exception e) {
Log.w(LOG_TAG, "Failed to start preview: " + e.getMessage());
}
}
/**
*
* #param index selects preview size from the list returned by CameraPreview.getSupportedPreivewSizes().
* #param width is the width of the available area for this view
* #param height is the height of the available area for this view
*/
public void setPreviewSize(int index, int width, int height) {
mCamera.stopPreview();
Camera.Parameters cameraParams = mCamera.getParameters();
boolean portrait = isPortrait();
Camera.Size previewSize = mPreviewSizeList.get(index);
Camera.Size pictureSize = determinePictureSize(previewSize);
if (DEBUGGING) { Log.v(LOG_TAG, "Requested Preview Size - w: " + previewSize.width + ", h: " + previewSize.height); }
mPreviewSize = previewSize;
mPictureSize = pictureSize;
boolean layoutChanged = adjustSurfaceLayoutSize(previewSize, portrait, width, height);
if (layoutChanged) {
mSurfaceConfiguring = true;
return;
}
configureCameraParameters(cameraParams, portrait);
try {
mCamera.startPreview();
} catch (Exception e) {
}
mSurfaceConfiguring = false;
}
public List<Camera.Size> getSupportedPreivewSizes() {
return mPreviewSizeList;
}
}
Xml file :
<FrameLayout
android:id="#+id/frm"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="#+id/frameCamera"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</FrameLayout>

android.hardware.Camera.setParameters getting runTime Exception(android)

I'm working on a project which has some camera functionalities. I have been facing a problem related to surface view. At first I implemented according to this article: Android SurfaceView Example. But this had some drawbacks: it captured the image in a stretched aspect ratio. I created a CustomView which Implemented SurfaceHolder.Callback to calculate the width and Height of the hosting view with mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes(); But now android.hardware.Camera.setParameters got me
public class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
Context activecontext;
private int cameraId = 1;
Preview(Context context, SurfaceView sv) {
super(context);
activecontext = context;
mSurfaceView = sv;
// addView(mSurfaceView);
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.
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);
}
}
}
Log.d(TAG,"cameraPreviewWidth:"+optimalSize.width+" cameraPreviewHeight:"+optimalSize.height);
return optimalSize;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if(mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
requestLayout();
parameters.setPictureSize(720,480);
mCamera.setParameters(parameters);
setCameraDisplayOrientation((MainActivity) activecontext,cameraId,mCamera);
mCamera.startPreview();
}
}
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
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_BACK) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
}
and on activity `setContentView(R.layout.main);
preview = new Preview(this, (SurfaceView)findViewById(R.id.surfaceView));
preview.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
((FrameLayout) findViewById(R.id.layout)).addView(preview);
preview.setKeepScreenOn(true);
preview.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
}); ..................................................................................................................................................#Override
protected void onResume() {
super.onResume();
int numCams = Camera.getNumberOfCameras();
if(numCams > 0){
try{
camera = Camera.open(0);
camera.startPreview();
preview.setCamera(camera);
} catch (RuntimeException ex){
Toast.makeText(ctx, getString(R.string.camera_not_found), Toast.LENGTH_LONG).show();
}
}
}
#Override
protected void onPause() {
if(camera != null) {
camera.stopPreview();
preview.setCamera(null);
camera.release();
camera = null;
}
super.onPause();
}
private void resetCam() {
camera.startPreview();
preview.setCamera(camera);
}
private void refreshGallery(File file) {
Intent mediaScanIntent = new Intent( Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaScanIntent.setData(Uri.fromFile(file));
sendBroadcast(mediaScanIntent);
}
ShutterCallback shutterCallback = new ShutterCallback() {
public void onShutter() {
// Log.d(TAG, "onShutter'd");
}
};
PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
// Log.d(TAG, "onPictureTaken - raw");
}
};
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
new SaveImageTask().execute(data);
resetCam();
Log.d(TAG, "onPictureTaken - jpeg");
}
};
private class SaveImageTask extends AsyncTask<byte[], Void, Void> {
#Override
protected Void doInBackground(byte[]... data) {
FileOutputStream outStream = null;
// Write to SD Card
try {
File sdCard = Environment.getExternalStorageDirectory();
File dir = new File (sdCard.getAbsolutePath() + "/camtest");
dir.mkdirs();
String fileName = String.format("%d.jpg", System.currentTimeMillis());
File outFile = new File(dir, fileName);
outStream = new FileOutputStream(outFile);
outStream.write(data[0]);
outStream.flush();
outStream.close();
Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length + " to " + outFile.getAbsolutePath());
refreshGallery(outFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
return null;
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if(mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
requestLayout();
parameters.setPictureSize(720,480);
mCamera.setParameters(parameters);
setCameraDisplayOrientation((MainActivity) activecontext,cameraId,mCamera);
mCamera.startPreview();
}
}
Here you are trying to hardcode the picture size. There is a possibility that this pic size may not be supported. Get the closest value from parameter.getSupportedPictureSizes(). This could be the issue.

android onPreviewFrame(byte[] data, Camera camera) always gives a noisy picture, does not gives the picture as in preview

I am just curious about correctly using setOneShotPreview() callback and correctly using onPreviewFrame(byte[] data, Camera camera) to get an image as it is displayed in preview. I have implemented all the code and its working but the resulting image is of no use. Below is my code please help me with what i am doing wrong.
public class MainActivity extends ActionBarActivity {
private static final String TAG = "CamTestActivity";
Preview preview;
Button buttonClick;
Camera camera;
String fileName;
Activity act;
Context ctx;
int frontCamera;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ctx = this;
act = this;
//requestWindowFeature(Window.FEATURE_NO_TITLE);
//getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
preview = new Preview(this, (SurfaceView)findViewById(R.id.surfaceView));
preview.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
((FrameLayout) findViewById(R.id.preview)).addView(preview);
preview.setKeepScreenOn(true);
frontCamera = findFrontFacingCamera();
buttonClick = (Button) findViewById(R.id.button_capture);
//camera.setOneShotPreviewCallback(cameraPreviewCallback);
buttonClick.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//camera.setOneShotPreviewCallback(cameraPreviewCallback);
//camera.takePicture(shutterCallback, rawCallback, jpegCallback);
camera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
Camera.Parameters parameters = camera.getParameters();
int format = parameters.getPreviewFormat();
//YUV formats require more conversion
if (format == ImageFormat.NV21 || format == ImageFormat.YUY2 || format == ImageFormat.NV16) {
int w = parameters.getPreviewSize().width;
int h = parameters.getPreviewSize().height;
Log.d("imageFormat",Integer.toString(format));
Log.d("imageNV21",Integer.toString(ImageFormat.NV21));
Log.d("imageYUY2",Integer.toString(ImageFormat.YUY2));
Log.d("imageNV16",Integer.toString(ImageFormat.NV16));
// Get the YuV image
YuvImage yuv_image = new YuvImage(data, format, w, h, null);
// Convert YuV to Jpeg
Rect rect = new Rect(0, 0, w, h);
ByteArrayOutputStream output_stream = new ByteArrayOutputStream();
yuv_image.compressToJpeg(rect, 100, output_stream);
byte[] byt = output_stream.toByteArray();
FileOutputStream outStream = null;
try {
// Write to SD Card
File folder = new File(Environment.getExternalStorageDirectory().toString()+"/SilentCamera/Images");
if(folder.exists()){
Log.d("creating folder","Folder already exists");
//Save the path as a string value
String extStorageDirectory = folder.toString();
Log.d("DirPath",extStorageDirectory);
fileName = String.format(extStorageDirectory+"/%d.jpg", System.currentTimeMillis());
Log.d("ImagePath",fileName);
outStream = new FileOutputStream(fileName);
//Uri uriSavedImage = Uri.fromFile(file);
outStream.write(byt);
outStream.flush();
outStream.close();
Log.d("SilentCam","Frame Received");
}
else{
folder.mkdirs();
String extStorageDirectory = folder.toString();
Log.d("DirPath",extStorageDirectory);
fileName = String.format(extStorageDirectory+"/%d.jpg", System.currentTimeMillis());
Log.d("ImagePath",fileName);
outStream = new FileOutputStream(fileName);
outStream.write(byt);
outStream.close();
Log.d("PassMainCamera", "onPictureTaken - wrote bytes: " + data.length);
Log.d("ImageUrl","Image Url added to database");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
}
});
//camera.startPreview();
}
});
}
#Override
protected void onResume() {
super.onResume();
camera = Camera.open(frontCamera);
camera.startPreview();
preview.setCamera(camera);
resetCam();
}
#Override
protected void onPause() {
if(camera != null) {
camera.stopPreview();
preview.setCamera(null);
camera.release();
camera = null;
}
super.onPause();
}
private void resetCam() {
camera.startPreview();
preview.setCamera(camera);
}
public static void setCameraDisplayOrientation(Context context,
int cameraId, android.hardware.Camera camera)
{
int result = MainActivity.getCameraDisplayOrientation(context, cameraId, camera);
if (android.os.Build.VERSION.SDK_INT <= 14)
{
camera.stopPreview();
camera.setDisplayOrientation(result);
camera.startPreview();
Log.i("Version<=14","inSettingOrirntation");
} else
{
camera.setDisplayOrientation(90);
Log.i("Version>14","inSettingOrirntation");
}
}// end setCameraDisplayOrientation
public static int getCameraDisplayOrientation(Context context,
int cameraId, android.hardware.Camera camera)
{
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = ((Activity) context).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;
}
return result;
}
// frinding id of front facing camera
private int findFrontFacingCamera() {
int foundId = -1;
int numCams = Camera.getNumberOfCameras();
for (int camId = 0; camId < numCams; camId++) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(camId, info);
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
foundId = camId;
break;
}
}
return foundId;
}
}
And this is my surface holder implementation,,
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
private Activity activity;
Context context;
Preview(Context _context, SurfaceView sv) {
super(_context);
context = _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();
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(params);
}
}
}
#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);
}
}
#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;
}
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) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
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;
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);
}
}
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(mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
String sceneMode = "SCENE_MODE_PORTRAIT";
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height);
Log.d("Preview Width",Integer.toString(mPreviewSize.width));
Log.d("Preview Height",Integer.toString(mPreviewSize.height));
Log.d("Preview Zoom",Integer.toString(parameters.getZoom()));
//parameters.setSceneMode(sceneMode);
//parameters.se
requestLayout();
//MainActivity.setCameraDisplayOrientation(context,Camera.CameraInfo.CAMERA_FACING_FRONT, mCamera);
mCamera.setParameters(parameters);
//mCamera.startPreview();
//mCamera.setDisplayOrientation(90);
}
}
}
This is all my code,,, Its been 3 days and still stuck at this problem,,,, every one says its working but not with me,,, i am testing it on samsung galaxy s with android 2.3.6 gingerbread,,,, please help me Thanks.
This is because the data provided as parameter is not in jpeg format. You need to convert it first:
Camera.Parameters parameters = camera.getParameters();
final int format = parameters.getPreviewFormat();
YuvImage im = new YuvImage( data, format, width, height, null );
ByteArrayOutputStream out = new ByteArrayOutputStream();
final Rect rect = new Rect( 0, 0, width, height );
im.compressToJpeg( rect, 100, out );
byte[] jpeg = out.toByteArray();

Android Camera preview in a fragment

Until now I have a full working code that plugs in a camera to see the preview of the front camera.
What I'm trying to do now is to get that camera working inside a Fragment.
Full code:
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
getFragmentManager().beginTransaction().add(R.id.mainLayout, new CameraExtractionFragment()).commit();
}
}
CameraExtractionFragment.java
public class CameraExtractionFragment extends Fragment {
private CameraExtraction mCameraExtraction;
Camera mCamera;
int mNumberOfCameras;
int cameraId;
int rotation;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCameraExtraction = new CameraExtraction(
this.getActivity().getBaseContext(),
this.getActivity().getWindowManager().getDefaultDisplay().getRotation()
);
// Find the total number of cameras available
mNumberOfCameras = Camera.getNumberOfCameras();
// Find the ID of the rear-facing ("default") camera
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < mNumberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
cameraId = i;
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return mCameraExtraction;
}
#Override
public void onResume() {
super.onResume();
// Use mCurrentCamera to select the camera desired to safely restore
// the fragment after the camera has been changed
mCamera = Camera.open(cameraId);
mCameraExtraction.setCamera(mCamera);
}
#Override
public void onPause() {
super.onPause();
if (mCamera != null)
{
mCamera.release();
}
}
// Modo en el que se pinta la cámara: encajada por dentro o saliendo los bordes por fuera.
public enum CameraViewMode {
/**
* Inner mode
*/
Inner,
/**
* Outer mode
*/
Outer
}
}
CameraExtraction.java
public class CameraExtraction extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "CameraExtraction";
Camera mCamera;
SurfaceHolder mHolder;
SurfaceView mSurfaceView;
int mNumberOfCameras;
int cameraId;
Rect desiredSize;
CameraViewMode cameraViewMode;
boolean mSurfaceCreated = false;
List<Size> mSupportedPreviewSizes;
int rotation;
Size mPreviewSize;
public CameraExtraction(Context context, int rotation) {
super(context);
this.rotation = rotation;
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
cameraViewMode = CameraViewMode.Inner;
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
if (mSurfaceCreated) requestLayout();
}
}
public void switchCamera(Camera camera) {
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
#SuppressLint("DrawAllocation")
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mSurfaceView == null ||mSurfaceView.getHolder() == null) return;
if (mSurfaceView.getHolder().getSurface() == null) {
// preview surface does not exist
return;
}
final int width = resolveSize(getSuggestedMinimumWidth(),
widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(),
heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getNearestPreviewSize(mCamera.new Size(widthMeasureSpec,heightMeasureSpec));
}
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (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);
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open(cameraId);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
if (mSurfaceView == null || mSurfaceView.getHolder() == null) return;
if (mSurfaceView.getHolder().getSurface() == null) {
// preview surface does not exist
return;
}
// set preview size and make any resize, rotate or
// reformatting changes here
Camera.Parameters param = mCamera.getParameters();
Point previewSize = new Point(640,480);
Camera.Size size = getNearestPreviewSize(mCamera.new Size(previewSize.x,previewSize.y));
param.setPreviewSize(size.width, size.height);
mCamera.setParameters(param);
rotation = setCameraDisplayOrientation(cameraId, mCamera);
// start preview with new settings
try {
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
}
});
mCamera.setPreviewDisplay(mSurfaceView.getHolder());
mCamera.startPreview();
} catch (Exception e) {
Log.d("AndroidControlSurfaceView",
"Error starting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null)
{
mCamera.stopPreview();
mCamera.release();
}
}
protected Rect getCameraViewSizeCompensated(Camera.Size cameraPreviewSize, Point hostViewSize) {
Rect toReturn=null;
float ratioWidth = hostViewSize.x / (float)cameraPreviewSize.width;
float ratioHeight = hostViewSize.y / (float)cameraPreviewSize.height;
switch (cameraViewMode){
case Inner:
if (ratioWidth < ratioHeight) {
int newHeight = (int)(cameraPreviewSize.height*ratioWidth);
int y = (hostViewSize.y - newHeight) / 2;
toReturn = new Rect(0, y, hostViewSize.x, y+newHeight);
} else {
int newWidth = (int)(cameraPreviewSize.width*ratioHeight);
int x = (hostViewSize.x - newWidth) / 2;
toReturn = new Rect(x, 0, x+newWidth,hostViewSize.y);
}
break;
case Outer:
if (ratioWidth < ratioHeight) {
int newWidth = (int)(cameraPreviewSize.width*ratioHeight);
int x = (hostViewSize.x - newWidth) / 2;
toReturn = new Rect(x, 0, x+newWidth,hostViewSize.y);
} else {
int newHeight = (int)(cameraPreviewSize.height*ratioWidth);
int y = (hostViewSize.y - newHeight) / 2;
toReturn = new Rect(0, y, hostViewSize.x, y+newHeight);
}
break;
}
return toReturn;
}
private Camera.Size getNearestPreviewSize(Camera.Size size) {
List<Camera.Size> availableSizes = mCamera.getParameters().getSupportedPreviewSizes();
if (availableSizes == null || availableSizes.size() <= 0) return null;
Camera.Size toReturn = availableSizes.get(0);
int distance = Math.abs(size.width*size.height - toReturn.width*toReturn.height);
for (int a=1; a<availableSizes.size(); a++) {
int temp = Math.abs(size.width*size.height - availableSizes.get(a).width*availableSizes.get(a).height);
if (temp < distance) {
distance = temp;
toReturn = availableSizes.get(a);
}
}
return toReturn;
}
public int setCameraDisplayOrientation(int cameraId, android.hardware.Camera camera) {
CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, 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;
}
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.setDisplayOrientation(result);
return result/90;
}
}
But when you run the application, no image is being showed in my device. Only a white screen. Note that, as I mentioned the camera is working in an activity not containing fragments.
So, why the main activity is shown with a white screen?
PS: Here you can download my code and test it.
At first - use FrameLayout for your camera preview.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
The second - no need to open camera two times. Your surfaceCreated method.
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
}
});
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
The third - no need to release camera two times. You did it in Fragment, just remove it from surfaceDestroyed.
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null)
{
// mCamera.stopPreview();
// mCamera.release();
}
}
And in your fragment.
#Override
public void onPause() {
super.onPause();
if (mCamera != null)
{
mCamera.stopPreview();
mCamera.release();
}
}
And you will see your camera preview in a fragmentas I see. Good luck!
It seems you have attribute cameraId in CameraExtractionFragment and CameraExtraction, but this is assigned a value only in CameraExtractionFragment.
You should remove CameraExtraction.cameraId and use CameraExtractionFragment.cameraId instead.

Categories

Resources