I have a custom camera in the app and the images that are taken on most of the devices look good but on galaxy nexus the story is different. Images are blurry in Galaxy nexus. I see grainy lines on Motorola Atrix as well. But Droid X, Droid Razr, HTC Evo, HTC incredible are showing good results. Any idea why it would happpen? This is what I have so far.
P.S.: I am using Auto focus in the activity.
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the
// preview.
try {
mCamera.setPreviewDisplay(holder);
Camera.Parameters parameters = mCamera.getParameters();
List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
mCamera.setParameters(parameters);
mCamera.startPreview();
} catch (IOException e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
try {
mCamera.startPreview();
} catch (Exception e) {
}
}
Its been a while I solved this problem. If I remember it correctly, I solved by adding the below lines while getting the camera instance.
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
int w = 0, h = 0;
for (Size size : sizes) {
if (size.width > w || size.height > h) {
w = size.width;
h = size.height;
}
}
parameters.setPictureSize(w, h);
Have you tried this one ?
if (cameraParameters.getSupportedSceneModes().contains(Camera.Parameters.SCENE_MODE_STEADYPHOTO)) {
cameraParameters.setSceneMode(Camera.Parameters.SCENE_MODE_STEADYPHOTO);
}
Related
How to solve the streching of image in my camera preview?
Camera Preview Class
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
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) {
try {
// create the surface and start camera preview
if (mCamera == null) {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
} catch (IOException e) {
Log.d(VIEW_LOG_TAG,
"Error setting camera preview: " + e.getMessage());
}
}
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.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) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
refreshCamera(mCamera);
}
public void setCamera(Camera camera) {
// method to set a camera instance
mCamera = camera;
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
// mCamera.release();
}
}
Maybe your CameraView's aspect ratio is not match with the aspect ratio of camera preview size.
You should caculate your CameraView's aspect ratio and use this aspect ratio to find best size for Camera.Parameters.setPreviewSize() method.
Try this
private Camera.Size getBestPreviewSize(Camera.Parameters parameters, int width, int height) {
Camera.Size result = null;
double ratio = width / height;
double w = 0, h = 0;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
w = size.width;
h = size.height;
if (w / h == ratio) {
if (result != null) {
if (w > result.width) {
result = size;
}
} else {
result = size;
}
}
}
return (result);
}
Whenever i use my Camera in Landscape Mode getting View in Portrait, I prepared two different layout for Portrait and Landscape Modes.
like still i am getting Preview in Portrait Mode not matter i am using Camera in Landscape or in Portrait Mode, but once i remove this line: mCamera.setDisplayOrientation(90); i am getting Preview in Landscape mode, either i use Camera in Landscape or in Portrait Mode
PreviewSurface.java:-
public class PreviewSurface extends SurfaceView implements
SurfaceHolder.Callback {
public static final String LOG_TAG = "CameraPreview";
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
// Constructor that obtains context and camera
#SuppressWarnings("deprecation")
public PreviewSurface(Context context, Camera camera) {
super(context);
this.mCamera = camera;
this.mSurfaceHolder = this.getHolder();
this.mSurfaceHolder.addCallback(this);
this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
this.mSurfaceHolder.setFixedSize(100, 100);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (IOException e) {
// left blank for now
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mCamera.stopPreview();
mCamera.release();
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
int width, int height) {
// start preview with new settings
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (Exception e) {
// intentionally left blank for a test
}
}
I suggest you to use : Configuration.ORIENTATION_LANDSCAPE to support Landscape Preview
Edit Answer:
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
Camera.Parameters parameters = mCamera.getParameters();
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
parameters.setRotation(90);
}
else {
// This is an undocumented although widely known feature
parameters.set("orientation", "landscape");
// For Android 2.2 and above
mCamera.setDisplayOrientation(0);
// Uncomment for Android 2.0 and above
parameters.setRotation(0);
}
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (IOException e) {
// left blank for now
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mCamera.stopPreview();
mCamera.release();
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
int width, int height) {
try {
Camera.Parameters parameters = mCamera.getParameters();
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
parameters.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
parameters.setRotation(90);
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
}
else {
// This is an undocumented although widely known feature
parameters.set("orientation", "landscape");
// For Android 2.2 and above
mCamera.setDisplayOrientation(0);
// Uncomment for Android 2.0 and above
parameters.setRotation(0);
}
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (IOException e) {
// left blank for now
}
}
I am creating a camera app but I have problems on startPreview, it sends me:
java.lang.RuntimeException: startPreview failed
here is my camera Activity:
public class CameraActivity extends Activity {
private Camera mCamera;
private CameraPreview mPreview;
private Target_Frame targetFrame;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_layout);
mCamera=getCameraInstance();
mPreview=new CameraPreview(this, mCamera);
FrameLayout preview=(FrameLayout)findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
/** Check if this device has a camera only if not specified in the manifest */
public boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
/**Check if the device has flash*/
public boolean checkFlash(Context context){
if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)){
//the device has flash
return true;
}else{
//no flash
return false;
}
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
releaseCamera();
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
releaseCamera();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
//Test if i have to put all this code like in onCreate
if(mCamera!=null){
return;
}
mCamera=getCameraInstance();
if(mPreview!=null){
return;
}
mPreview=new CameraPreview(this, mCamera);
FrameLayout preview=(FrameLayout)findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}}
And here is my SurfaceView code:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
// 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) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
Parameters parameters= mCamera.getParameters();
parameters.setPreviewSize(w, h);
mCamera.setParameters(parameters);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
And here is my error log:
12-01 13:17:01.135: E/AndroidRuntime(1161): FATAL EXCEPTION: main
12-01 13:17:01.135: E/AndroidRuntime(1161): java.lang.RuntimeException: startPreview
12-01 13:17:01.135: E/AndroidRuntime(1161): at com.example.prueba.CameraPreview.surfaceCreated(CameraPreview.java:36)
I have solved deleting some lines in surfaceChanged
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
Log.d("Function", "surfaceChanged iniciado");
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
So the error must be in i one of these lines:
Parameters parameters= mCamera.getParameters();
parameters.setPreviewSize(w, h);
mCamera.setParameters(parameters);
Someone could explain me what was wrong in those lines?
Is (w, h) a valid preview size for your camera?
You can use mCamera.getParameters().getSupportedPreviewSizes() to get all of the valid preview sizes.
Its late, but if someones looking for the answer
The variables w and h are not the optimal preview sizes . You can get optimal preview sizes using the function
public static 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.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
and you can call the function using
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
..
size=getOptimalPreviewSize(parameters.getSupportedPreviewSizes(), w, h);
parameters.setPreviewSize(size.getWidth(), size.getHeight());
..
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.getParameters().getSupportedPreviewSizes();
mCamera.startPreview();
Log.d(TAG, "Camera preview started.");
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
I had this error, and it's because I didn't call releaseCamera on the onPause the first time I start my app.
After a reboot, everything works fine ^^
I have a customer with an LG Optimus Black (android 2.2.2) that have the camera preview every time black. On other devices all is working fine. Is there some issue on this phone or someone have a solution? The code for my camera preview is the follow.
SurfaceHolder.Callback mySurfaceHolderCallback = new SurfaceHolder.Callback()
{
#Override
public void surfaceCreated(SurfaceHolder holder)
{
Log.i("GMG", "surfaceCreated");
try
{
mCamera = Camera.open();
holder.setFormat(PixelFormat.TRANSLUCENT);
mCamera.setPreviewDisplay(holder);
}
catch (IOException e)
{
if (mCamera == null) return;
mPreviewRunning= false;
mCamera.release();
mCamera = null;
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
Log.i("GMG", "surfaceDestroyed");
if (mCamera != null)
{
mCamera.stopPreview();
mPreviewRunning= false;
mCamera.release();
mCamera = null;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
Log.i("GMG", "surfaceChanged");
if (mCamera != null)
{
if(mPreviewRunning) mCamera.stopPreview();
Camera.Parameters p = mCamera.getParameters();
//Angolo visivo della fotocamera
angoloVisualeX = p.getHorizontalViewAngle();
angoloVisualeY = p.getVerticalViewAngle();
//Formati della preview
supportedPreviewSize = p.getSupportedPreviewSizes();
int preview_width = supportedPreviewSize.get(supportedPreviewSize.size()-1).width;
int preview_height = supportedPreviewSize.get(supportedPreviewSize.size()-1).height;
p.setPreviewSize(preview_width, preview_height);
//Set camera orientation
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
if(display.getRotation() == Surface.ROTATION_0) mCamera.setDisplayOrientation(90);
if(display.getRotation() == Surface.ROTATION_270) mCamera.setDisplayOrientation(180);
mCamera.setParameters(p);
mCamera.startPreview();
mPreviewRunning = true;
}
}
};
Best regards.
I have solved, I don't know why, but witha big camera preview I dont have the problem
change
int preview_width = supportedPreviewSize.get(supportedPreviewSize.size()-1).width;
int preview_height = supportedPreviewSize.get(supportedPreviewSize.size()-1).height;
with
int preview_width = supportedPreviewSize.get(0).width;
int preview_height = supportedPreviewSize.get(0).height;
I'm using a SurfaceView with a SurfaceHolder to start off with a camera preview in my test app.
public class TextLocatorActivity extends Activity {
private Preview pvw;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
pvw = new Preview(this);
setContentView(pvw);
}
I want to use the CameraPreview (comes with the SDK Samples for SDK version 7). A click on the UI takes a picture. Here's the Preview class:
public class Preview extends SurfaceView implements OnClickListener, SurfaceHolder.Callback {
SurfaceHolder holder;
Camera cam;
final static String TAG = "TextLocator:Preview";
Preview(Context context) {
super(context);
holder = getHolder();
holder.addCallback(this);
this.setOnClickListener(this);
// seems to be required (although the docs state, this enum is deprecated, as the type will be chosen automatically...
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
cam = Camera.open();
try {
Camera.Parameters params = cam.getParameters();
params.set("orientation", "landscape");
Camera.Size bestSize = getBestPreviewSize(480, 320);
params.setPreviewSize(bestSize.width, bestSize.height);
cam.setParameters(params);
// where to draw:
cam.setPreviewDisplay(holder);
} catch (IOException exception) {
cam.release();
cam = null;
// TODO: add more exception handling logic here
}
}
private Camera.Size getBestPreviewSize(int width, int height)
{
// checks for supported sizes close to the demanded values - implemented.
}
public void surfaceDestroyed(SurfaceHolder holder) {
cam.stopPreview();
cam.release();
cam = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters parameters = cam.getParameters();
parameters.setPreviewSize(w, h);
cam.setParameters(parameters);
cam.startPreview();
}
Camera.PictureCallback picCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] bytes, Camera arg1) {
synchronized(holder) {
Canvas c = null;
try {
c = holder.lockCanvas();
Paint paint = new Paint();
paint.setAntiAlias(false);
paint.setARGB(200, 120, 180, 0);
c.drawLine(10, 10, c.getWidth() - 10, c.getHeight() - 10, paint);
}
catch (Exception e) {
Log.d(TAG, "Exception: " + e.getMessage());
// IllegalArguementException Surface Type is SURFACE_TYPE_PUSH_BUFFERS
}
finally {
holder.unlockCanvasAndPost(c);
}
}
}
};
public void onClick(View v)
{
cam.takePicture(null, null, picCallback);
}
}
Next I'm trying to do some additional painting to the corresponding Canvas of the SurfaceHolder. Therefore I'm calling canvas = holder.lockCanvas(). This will result in an IllegalArgumentException with the Message:
Surface type is SURFACE_TYPE_PUSH_BUFFERS
Now, docs state that those Surface Types are deprecated, the value set will be ignored. However, the camera preview only works, if I set the type to this specific value.
How can I achieve drawing on the Canvas of the SurfaceView the picture taken is displayed in? Or should that be put on a different layer/view?
You cannot both display the camera preview and draw with a Canvas. You have to do one or the other.