In My camera app i am trying to set the preview surfaceView, imagePreview and Image Sizes however no matter what i change the live preview always occupies the entire activity. there doesn't appear to be any distortion but the problem is i need to attach an overlay image that is present in the preview and must be saved in the same position in the end image.
Shouldn't the Preview size be taken in relation the the end image size as i am passing params.getPictureSize(). width and height into the getOptimalPreviewSize() method?
surfaceView Layout
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">
<SurfaceView
android:id="#+id/surfaceView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
set Image size
Parameters params = camera.getParameters();
List <Camera.Size>sizes = params.getSupportedPictureSizes();
if(sizes.size() > 1){
params.setPictureSize(sizes.get(2).width,sizes.get(2).height);// get can be value 0 - 5
camera.setParameters(params);
}
note i am manually setting different sizes here for testing purposes
Set Preview Size
List<Camera.Size> supportedPreviewSizes = params.getSupportedPreviewSizes();
Camera.Size camPreviewSize = getOptimalPreviewSize(supportedPreviewSizes, params.getPictureSize().width , params.getPictureSize().height);
params.setPreviewSize(camPreviewSize.width, camPreviewSize.height);
camera.setPreviewDisplay(surfaceHolder);
camera.setParameters(params);
camera.startPreview();
getOptimalPreviewSize()
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.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;
}
Related
I have been trying to figure this out for a while, but for some reason, when I start recording a video with the camera, the preview zooms in. I have the following code from some examples:
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters myParameters = mCamera.getParameters();
List<Camera.Size> sizes = myParameters.getSupportedPreviewSizes();
Camera.Size myBestSize = getBestPreviewSize(sizes, width, height);
if (myBestSize != null) {
myParameters.setPreviewSize(myBestSize.width, myBestSize.height);
myParameters.setVideoStabilization(false);
mCamera.setParameters(myParameters);
mCamera.startPreview();
mCamera.unlock();
}
}
private Camera.Size getBestPreviewSize(List<Camera.Size> sizes, int width, int height) {
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) width / height;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = height;
// Find size
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
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;
}
But the preview still zooms in when recording a video. I tried manually setting the preview size to 1280x720, however, it doesn't work on all devices that I tested, with some showing a black SurfaceView.
Is there any way to prevent the preview from zooming in when recording a video? None of the solutions here at StackOverflow seem to work.
EDIT: I tried created a custom SurfaceView with its own onMesaure method, but now I get a -19 error when I start my MediaRecorder. (disregard the -16 in the bounty)
I am confused about the kind of zoom you're talking about, could be a software zoom, or the autofocus maybe, so I'll suggest different potential tips leading to the final solution :
Implement mCamera.setZoomChangeListener, eg:
mCamera.setZoomChangeListener(new Camera.OnZoomChangeListener() {
#Override public void onZoomChange(int i, boolean b, Camera camera) {
Log.e("StackOverflow","Zoom just changed !");
// Inspect things from here
}
});
Disable the smooth zoom :
mCamera.stopSmoothZoom(); // My device doesn't support it, but maybe your device does
Inspect all of yours Camera.Parameters:
Log.e("StackOverflow", "All Camera parameters :");
for(String s : mCamera.getParameters().flatten().split(";"))
Log.e("StackOverflow", s + "\n");
Then switch anything that could be zoom related, eg :
Camera.Parameters parameters = mCamera.getParameters();
parameters.setZoom(100); // My device support some values in the range 100 | 400
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
parameters.setVideoStabilization(false);
// Don't forget to add the new parameters to the camera :
mCamera.setParameters(parameters);
Regards
You probably have setVideoStabilization(true). In high res e.g. 4K, if you enable this, it will create this jump zoom.
I am developing a camera filter app, and my aim is to have a square camera preview (crop it, and get the center square), and take photos as square.
I am using the Google API's getOptimalPreviewSize method, which is:
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
I am testing on an LG G4 device, and there is no problem with the back-facing camera. All the apps (Retrica, Instagram, device's Camera app) including mine are showing the same preview. But, when it comes to front facing camera, then Instagram and Retrica has wider angle, and device's Camera app and my application has narrower angle.
I don't know how to fix this, because even when I get the preview as 1920*1080 (maximum available size for front camera), the preview is like "zoomed in".
Any suggestions how to fix this problem? (my app is showing exact scene that the device's Camera app shows, but Instagram-Retrica shows kinda zoomed-out scene.
Thank you.
(PS: My application is getting preview on SurfaceView, the typical way)
I am making a Camera app in Android and have used the following function to get the preview size:
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;
}
And I set the size like this:
Size s = getOptimalPreviewSize(parameters.getSupportedPreviewSizes(), w, h);
parameters.setPreviewSize(s.width, s.height);
But the problem is that when I run my app, the camera preview quality is really poor. How do i get the same preview quality as I get when I run my default camera app on my phone, in other words, I want a high resolution Camera preview in my app.
I am even not sure whether the preview size is the cause of this problem.
NOTE: The function to get the preview size is taken from sample programs from Android Docs.
That algorithm is not the greatest.
The default algorithm in my CWAC-Camera library is now:
public static Camera.Size getBestAspectPreviewSize(int displayOrientation,
int width,
int height,
Camera.Parameters parameters,
double closeEnough) {
double targetRatio=(double)width / height;
Camera.Size optimalSize=null;
double minDiff=Double.MAX_VALUE;
if (displayOrientation == 90 || displayOrientation == 270) {
targetRatio=(double)height / width;
}
List<Size> sizes=parameters.getSupportedPreviewSizes();
Collections.sort(sizes,
Collections.reverseOrder(new SizeComparator()));
for (Size size : sizes) {
double ratio=(double)size.width / size.height;
if (Math.abs(ratio - targetRatio) < minDiff) {
optimalSize=size;
minDiff=Math.abs(ratio - targetRatio);
}
if (minDiff < closeEnough) {
break;
}
}
return(optimalSize);
}
This:
Takes into account portrait versus landscape
Starts with the highest resolution previews and works its way down
Can be tailored via closeEnough to opt for higher resolution as opposed to best matching the aspect ratio of the preview area
I am automating one of the video app in android. In order to do it, I need to set the video resolution to highest.
I know that in regular camera, I can set the values in
/data/data/com.android.gallery3d/shared_prefs/com.android.gallery3d_preferences_0.xml
But the values I set there are just set for the camera not for the video. Any idea where the video resolution values are stored?
If there is any ADb command to store video encoding resolution then it would be even better.
Following is the adb command that I used but does nto seem to work:
adb shell am start -a android.media.action.VIDEO_CAPTURE --ei android.intent.extras.CAMERA_FACING 1 --ei android.intent.extras.EXTRA_VIDEO_QUALITY 1 -n com.android.gallery3d/com.android.camera.CameraActivity
I also found recently that
/data/data/com.android.gallery3d/shared_prefs/com.android.gallery3d_preferences_0.xml
file contains the value for the highest resolution and the key name is :
"pref_video_quality_key" but somehow, it only sets back camera value and does not do front camera value
You dont have to look for that, but ask the system.
Every device has a sort of supported resolutions. You can select the best available size for your requirements:
What to do?
Step 1.
you have to check for the supported sizes. You can do it with
Camera.Parameters p = myCamera.getParameters();
List<Size> previewsizes = p.getSupportedPreviewSizes();
List<Size> videosizes = p.getSupportedVideoSizes();
and then, you can choose one. If you want to automatize this, you can go further, and follow the
Step 2
write a function to select the best available size, which will receive the supported sizes, and the desired size. Yo can get the size whose ratio is closer to the desired, and if none is good enough, you get the one which height is closed to the desired, or you can get just the biggest something like:
public static final int BEST_RATIO=0;
public static final int IMPORTANT_HEIGHT=2;
public static final int IMPORTANT_WIDTH=1;
public static final int BIGGEST=3;
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h, int mode) {
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;
if (mode==BEST_RATIO)
{ 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);
}
}
}
if (mode= IMPORTANT_HEIGHT) { //you can do other for width
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
if (mode=IMPORTANT_WIDTH) { //you can do other for width
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.Width - targetWidth) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.Width - targetWidth);
}
}
}
else {
minDiff = 0;
for (Size size : sizes) {
if ( size.height * size.width > minDiff ) {
optimalSize = size;
minDiff = size.height * size.width ;
}
}
}
return optimalSize;
}
And the last step, set the parameters
Step 3
private int desiredwidth=640, desiredheight=360;
Size optimalPreviewSize = getOptimalPreviewSize(previewsizes, desiredwidth, desiredheight,BIGGEST);
Size optimalVideoSize = getOptimalPreviewSize(videosizes, desiredwidth, desiredheight,BIGGEST);
p.setPreviewSize(optimalPreviewSSize.width, optimalPreviewSSize.height);
CamcorderProfile profile = CamcorderProfile.get(cameraid, CamcorderProfile.QUALITY_LOW);
profile.videoFrameHeight= optimalVideoSize.height;
profile.videoFrameWidth=optimalVideoSize.with;
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setVideoSize(optimalVideoSize.width, optimalVideoSize.height);
myCamera.setParameters(p);
I read that you need to get the parameters.getSupportedPreviewSizes() and parameters.getSupportedPictureSizes() so I did this
Camera.Parameters pic = mCamera.getParameters();
List<Size> pic2 = pic.getSupportedPictureSizes();
Camera.Parameters p = mCamera.getParameters();
List<Size> previews = p.getSupportedPreviewSizes();
Size preview = getOptimalPreviewSize(previews, pic2.get(0).width,pic2.get(0).height);
with this to get optimal preview
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.05;
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;
}
then
mFrameLayout.getLayoutParams().height = preview.height;
mFrameLayout.getLayoutParams().width = preview.width;
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mFrameLayout.addView(mPreview);
I was hoping to get similar preview to as the Camera Intent with custom view similar to instagram, but this shows a rectangle that is flattened as a preview. Is there a way to get the preview and picture size of the default camera and set it to the custom camera?
For some reason when i take a picture there is more content in the saved pic on the left and right than what you see in the preview Layout it looked like it was zoomed but checked zoom and it is at 0. Any tips on how to fix this?
Just another question, can you use the Camera intent on a Layout instead of it opening the default camera?