I m trying to record a video but when i start recording it using media recorder it gets stretched horizontally.I have tried to applied lot of soltuion but nothing works for my code yet.
This is what i have tried to do so far to resolve this issue. Can anyone suggest any solution.Thanks
public class MyCameraSurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public MyCameraSurfaceView(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);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// If your preview can change or rotate, take care of those events
// here.
// Make sure to stop the preview before resizing or reformatting it.
System.out.println("inside surfaceChanged");
if (mHolder.getSurface() == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
e.printStackTrace();
}
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
////////////////////////////////////////////////////////////
/*if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
}*/
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw
// the preview.
System.out.println("inside surfaceCreated");
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void setCamera(Camera camera) {
// method to set a camera instance
mCamera = camera;
}
public void refreshCamera(Camera camera) {
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
setCamera(camera);
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(VIEW_LOG_TAG,
"Error starting camera preview: " + e.getMessage());
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
System.out.println("inside onMeasure");
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, 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.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;
}
private boolean prepareMediaRecorder() {
try {
myCamera = getCameraInstance();
setCameraDisplayOrientation(VideoRecordingActivity.this, cameraId, myCamera);
myCamera.unlock();
mediaRecorder = new MediaRecorder();
mediaRecorder.setCamera(myCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
if (cameraId == 1) {
mediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_LOW));
mediaRecorder.setOrientationHint(270);
} else if (cameraId == 0) {
mediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_HIGH));
mediaRecorder.setOrientationHint(orientation);
}
prRecordedFile = new File(Environment.getExternalStorageDirectory()
+ "/VideoApp/Videos/"
+ String.valueOf(System.currentTimeMillis()) + ".mp4");
mediaRecorder.setOutputFile(prRecordedFile.getPath());
// mediaRecorder.setVideoSize(320, 240);
mediaRecorder.setVideoFrameRate(15); // might be auto-determined
mediaRecorder.setMaxDuration(900000); // Set max duration 900
// sec=15min.
mediaRecorder.setMaxFileSize(500000000); // Set max file size
mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder()
.getSurface());
mediaRecorder.prepare();
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (Exception e) {
releaseMediaRecorder();
return false;
}
return true;
}
enter code here
This is solve my issue, you can try this:
Whatever you are setting preview size in surfaceChanged() method, set as it is also in MediaRecorder class.
Add this line while you are preparing MediaRecorder
mMediaRecorder.setVideoSize(mPreviewSize.width, mPreviewSize.height);
Related
When i try to record using my custom camera its preview showing normally and in good shape but when i click on start button preview changed and stretching.
public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
private int mRatioWidth = 0;
private int mRatioHeight = 0;
public MyCameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for(Camera.Size str: mSupportedPreviewSizes)
Log.e("Ji", str.width + "/" + str.height);
setKeepScreenOn(true);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int weight,
int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
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){
// ignore: tried to stop a non-existent preview
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// The Surface has been created, now tell the camera where to draw the preview.
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (IOException e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
Here is onMesuare method for calculations
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
if (0 == mRatioWidth || 0 == mRatioHeight) {
setMeasuredDimension(width, height);
} else {
if (width < height * mRatioWidth / mRatioHeight) {
setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
} else {
setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
}
}
And For getting Size of Screen here is method.
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;
}
}
Thanks for help in advance...
I am able to rotate the camera preview from portrait to landscape by using the setDisplayOrientation(90) method but preview won't look realistic and is stretched in landscape mode. I have gone through multiple posts related to the same but not able to succeed with required view. I am trying this on the rooted android Jellybeans version.
Can you please suggest the ways to improve the preview in landscape mode?
below is my code set of CameraPreview and Activity class:
import java.io.IOException;
import java.util.List;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = null;
private SurfaceHolder mHolder;
private Camera mCamera;
List<Size> sizes;
Camera.Size mPreviewSize;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
setCamera(mCamera);
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
public void setCamera(Camera camera) {
if (mCamera == camera) { return; }
mCamera = camera;
if (mCamera != null) {
requestLayout();
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
if(mCamera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = mCamera.getParameters();
sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
mCamera.setDisplayOrientation(90);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(parameters);
}
/*
Important: Call startPreview() to start updating the preview surface. Preview must
be started before you can take a picture.
*/
mCamera.startPreview();
}
}
public 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;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
sizes = mCamera.getParameters().getSupportedPreviewSizes();
if (sizes != null) {
mPreviewSize = getOptimalPreviewSize(sizes, width, height);
}
}
}
public class TestCameraActivity extends Activity {
public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;
protected static final String TAG = null;
private PictureCallback mPicture;
/** Called when the activity is first created. */
Context ctx;
Camera mCamera;
CameraPreview mPreview;
Camera.Size optimalSize;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
boolean cameraAvailable = checkCameraHardware(this);
if(cameraAvailable){
mCamera = getCameraInstance();
}else Toast.makeText(this, "No Camera Available",Toast.LENGTH_LONG).show();
double aspectRatio =0;
mPreview = new CameraPreview(this,mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
mPicture = getPictureCallback();
if(mCamera != null){
//Setting the camera's aspect ratio
Camera.Parameters parameters = mCamera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
optimalSize = mPreview.getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
aspectRatio = (float)optimalSize.width/optimalSize.height;
}
// if(optimalSize!= null){
// FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
// preview.setLayoutParams(params);
// LayoutParams surfaceParams = new LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
// mPreview.setLayoutParams(surfaceParams);
// }
mPreview.setCamera(mCamera);
Button capture = (Button) findViewById(R.id.button_capture);
capture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
mCamera.takePicture(null, null, mPicture);
}
});
}
private PictureCallback getPictureCallback() {
PictureCallback picture = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d(TAG, "Error creating media file, check storage permissions: " );
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
};
return picture;};
#Override
protected void onPause() {
super.onPause();
releaseCamera(); // release the camera immediately on pause event
}
private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
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
}
/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyCameraApp");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
} else if(type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"VID_"+ timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;`enter code here`
} else {
// no camera on this device
return false;
}
}
}
The value that you pass to setDisplayOrientation is not fixed: it's dependent on the individual camera's orientation (where the "top" of the camera is) as well as the current orientation of the device itself. By setting it to a constant value, your preview may look correct in one orientation but in another will be as you described.
The documentation provides the math that you need to take both into account when setting this value:
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_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);
}
Android Version 4.4.2 Samsung Note 8:
I have made a custom camera using surface view.
I may able to capture image and store it in SDcard.
It looks perfect in all devices I checked i.e Nexus 7, Micromax Turbo, Canvas Hd, Moto G, Moto E.
But In samsung Note 8(4.4.2 - Kitkat), Image got tile 1/8 times. some times 2/8.
When user captured a photo and stored it in SdCard folder, It contains tiled image.
Like this: http://prntscr.com/5xoc5e
Camera Capturing Code:
OnCapture Button Click:
camera.takePicture(null, null, mPicture);
PictureCallback mPicture = new PictureCallback()
{
#Override
public void onPictureTaken(byte[] data, Camera camera)
{
mrawDataCapturedImg = data;
try
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bmp = BitmapFactory.decodeByteArray(mrawDataCapturedImg, 0, mrawDataCapturedImg.length,options);
mimgPreview.setImageBitmap(bmp);
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
Storing Image Code:
File pictureFile = new File(mediaStorageDir.getPath()
+ File.separator + saveName + ".jpg");
try
{
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(mrawDataCapturedImg);
fos.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
MyCameraPreview Class:
public class MyCameraPreview extends SurfaceView implements SurfaceHolder.Callback
{
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
PreviewCallback mPreviewCallback;
AutoFocusCallback mAutoFocusCallback;
#SuppressWarnings("unused")
private String TAG = "camera";
private Activity context;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
#SuppressWarnings("deprecation")
public MyCameraPreview(Activity context, Camera camera, AutoFocusCallback autoFocusCB,PreviewCallback previewCallback)
{
super(context);
mPreviewCallback = previewCallback;
this.context = context;
this.mCamera = camera;
mAutoFocusCallback = autoFocusCB;
this.mSurfaceHolder = MyCameraPreview.this.getHolder();
this.mSurfaceHolder.addCallback(MyCameraPreview.this);
this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height)
{
try
{
if(mCamera!=null)
{
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
setCameraDisplayOrientation(0, mCamera);
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.setPreviewCallback(mPreviewCallback);
mCamera.startPreview();
mCamera.autoFocus(mAutoFocusCallback);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder)
{
try {
if (mCamera != null)
{
mCamera.setPreviewDisplay(surfaceHolder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder)
{
if (mCamera != null)
{
if(mAutoFocusCallback != null)
mCamera.cancelAutoFocus();
mCamera.stopPreview();
}
}
public void setCameraDisplayOrientation(
int cameraId, android.hardware.Camera camera)
{
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = 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;
}
camera.setDisplayOrientation(result);
}
public void setCamera(Camera camera)
{
mCamera = camera;
if (mCamera != null)
{
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
}
}
#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);
}
}
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;
}
}
I have added FrameLayout which display camera preview in it, but the preview is getting stretched.
I have tried solution given in https://stackoverflow.com/a/19592492/1597844 but that does not help either.
Can you help know what is wrong in my code?
Output that I am getting is
Upper Image gets skewed horizontally (portrait mode) and the below one gets stretched vertically (Landscape mode)
Code that I am using is
mCamera = Camera.open(findBackFacingCamera());
Camera.Parameters parameters = mCamera.getParameters();
parameters.set("jpeg-quality", 100);
parameters.setPictureFormat(PixelFormat.JPEG);
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(parameters);
mPicture = getPictureCallback();
mPreview = new CameraPreview(myContext, mCamera);
backCameraPreview.removeAllViews();
backCameraPreview.addView(mPreview);
Method for getting optimal preview size
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;
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;
}
My xml looks like this
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="2">
<FrameLayout
android:id="#+id/dual_camera_capture_activity_ll_back_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#android:color/white"
android:orientation="horizontal"
android:padding="10dp" />
<FrameLayout
android:id="#+id/dual_camera_capture_activity_fl_front_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_weight="1"
android:background="#android:color/white"
android:orientation="horizontal"
android:padding="10dp" />
</LinearLayout>
This is my CameraPreview class that is SurfaceView
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private final Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private static String TAG = "Dual Camera";
private float mDist;
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
mCamera = camera;
mHolder = getHolder();
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mHolder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surface created");
// The Surface has been created, now tell the camera where to draw the
// preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "surface destroyed");
this.getHolder().removeCallback(this);
}
public void refreshCamera(Camera camera) {
setCamera(camera);
if (mCamera != null) {
Display display = ((Activity) mContext).getWindowManager().getDefaultDisplay();
if (mHolder.getSurface() == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
e.printStackTrace();
}
Camera.Parameters parameters = mCamera.getParameters();
if (display.getRotation() == Surface.ROTATION_0) {
mCamera.setDisplayOrientation(90);
}
if (display.getRotation() == Surface.ROTATION_90) {
}
if (display.getRotation() == Surface.ROTATION_180) {
}
if (display.getRotation() == Surface.ROTATION_270) {
}
mCamera.setParameters(parameters);
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 width, int height) {
refreshCamera(mCamera);
}
public void setCamera(Camera camera) {
mCamera = camera;
}
}
Can you tell me what I am doing wrong?
This is because of less resolution of preview size
Set preview size hard code parameters.setPreviewSize(1920, 720);
I'm using a custom camera preview on my app, it works fine in almost all devices, for HTC-One I'm getting a bad cut, the original photo doesn't match what the preview shows on the top.
It only happens on this device, this is the code of my preview camera and the picture about what's going on.
Thanks in advance for any help someone can give me.
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private final String TAG = "CameraPreview";
private SurfaceHolder mHolder;
private Camera mCamera;
private Context context;
private Camera.Size mPreviewSize;
private List<Camera.Size> mSupportedPreviewSizes;
public CameraPreview(Context context) {
super(context);
this.context = context;
mHolder = getHolder();
mHolder.addCallback(this);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for (Camera.Size str : mSupportedPreviewSizes) {
Log.e(TAG, str.width + "/" + str.height);
}
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
float ratio;
if (mPreviewSize.height >= mPreviewSize.width) {
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
} else {
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
}
setMeasuredDimension(width, (int) (width * ratio));
}
#Override
public void surfaceCreated(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
}
// 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);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void setFlash(String flashMode) {
Camera.Parameters params = mCamera.getParameters();
params.setFlashMode(flashMode);
mCamera.setParameters(params);
}
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;
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 - h) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - h);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - h) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - h);
}
}
}
return optimalSize;
}
public void switchCamera(Camera camera) {
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
camera.setDisplayOrientation(90);
} else if (display.getRotation() == Surface.ROTATION_270) {
camera.setDisplayOrientation(180);
}
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
}
Camera preview size and picture size are two different parameters, which you can update through setPictureSize() and setPreviewSize() APIs. But if user doesn't change these sizes, it will use default values.
In this case you are updating the preview size by calculating optimum preview size based on some aspect ratio. But you are not updating picture size, so it will be using default picture size.
If picture size and preview size aspect ratios are different, definitely the captured image looks different from preview. So update the picture size also by calculating optimum picture size with same aspect ratio as preview size.