Android camera preview flicker - android

I'm facing a problem with quite a simple Android camera preview using SurfaceView.
I don't know why but whenever the SurfaceView size/position falls outside the visible area, the preview starts to flicker. The intensity of this increases if the objects seen by the camera are moving.
Device: Nexus 7 (first edition), Android 4.4.2
Application targeted for API16.
As soon as the flickering occurs, in the log plenty of messages like below are displayed:
I/hwcomposer( 127): Setting interactive mode: Off
I/hwcomposer( 127): Setting interactive mode: On
I/hwcomposer( 127): Setting interactive mode: Off
I/hwcomposer( 127): Setting interactive mode: On
I/hwcomposer( 127): Setting interactive mode: Off
The problem started on Sony Tablet Z and was reproduced on Nexus 7.
For some reason I don't want to discuss here I don't have full control if the preview area falls outside the visible are. As you can see, even a small preview with (-100, -100) left/top margin causes problems.
The app is very simple. Just one class and XML layout file:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<!--
android:layout_width="1022px"
android:layout_height="1363px"
android:layout_marginLeft="0px"
android:layout_marginTop="0px"
-->
<FrameLayout
android:id="#+id/camera_preview_container"
android:layout_width="500px"
android:layout_height="500px"
android:layout_marginLeft="-100px"
android:layout_marginTop="-100px">
<SurfaceView
android:id="#+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</FrameLayout>
and the activity code:
package com.example.surfaceviewtest;
import java.io.IOException;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.Menu;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
public class MainActivity extends Activity implements SurfaceHolder.Callback {
private final String TAG = "com.example.surfaceviewtest";
private Camera camera;
private boolean isPreviewing = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((SurfaceView)this.findViewById(R.id.surface_view)).getHolder().addCallback(this);
}
#Override
protected void onResume() {
Log.d(TAG, "onResume");
super.onResume();
camera = Camera.open(0);
Camera.Parameters cameraParameters = camera.getParameters();
Size previewSize = cameraParameters.getPreviewSize();
Log.d(TAG, String.format("Preview size: width %d height %d", previewSize.width, previewSize.height));
Size pictureSize = cameraParameters.getPictureSize();
Log.d(TAG, String.format("Picture size: width %d height %d", pictureSize.width, pictureSize.height));
/*cameraParameters.setPictureSize(320, 240);
cameraParameters.setPreviewSize(176, 144);
camera.setParameters(cameraParameters);*/
}
#Override
protected void onPause() {
Log.d(TAG, "onPause");
super.onPause();
stopPreview();
camera.release();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated");
try {
setCameraDisplayOrientation();
setCameraOrientation();
camera.setPreviewDisplay(holder);
startPreview();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.d(TAG, String.format ("surfaceChanged: format %d width %d height %d", format, width, height));
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "surfaceDestroyed");
stopPreview();
}
private void startPreview() {
if (isPreviewing)
return;
camera.startPreview();
}
private void stopPreview() {
if (isPreviewing == false)
return;
camera.stopPreview();
isPreviewing = false;
}
public int getDisplayOrientation() {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(0, info);
int rotation = ((WindowManager) getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
int degrees = orientationToAngle(rotation);
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;
}
protected void setCameraDisplayOrientation() {
int rotation = getDisplayOrientation();
camera.setDisplayOrientation(rotation);
}
protected static int orientationToAngle(int orientation) {
switch (orientation) {
case Surface.ROTATION_0:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return 270;
}
return 0;
}
protected void setCameraOrientation() {
int orientation = ((WindowManager) getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
int degrees = orientationToAngle(orientation);
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(0, info);
degrees = (degrees + 45) / 90 * 90;
int rotation = 0;
if (info.facing != CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - degrees + 360) % 360;
} else {
rotation = (info.orientation + degrees) % 360;
}
Camera.Parameters parameters = camera.getParameters();
parameters.setRotation(rotation);
camera.setParameters(parameters);
}
}

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

Android Image/Video incorrectly rotated 90 degrees counter clockwise

I have an app that that exposes the android Camera API, my goal is to use the Camera in my activity “ScanVinFromBarcodeActivity” , in order to scan barcodes using (zxing liberary).
The issue I'm facing is that the Camera output on the preview (SurfaceView) seems to be rotated 90 degrees counter clockwise (portrait & landscape orientations).
See the snapshot of my screen ( As you can see the people and my computer are rotated 90 degrees counter clockwise???:
By the way my device is a Galaxy S3.
I’m using the following code in my PreviewCamera class which extends SurfaceView
The relevant snippet:
surfaceChanged(SurfaceHolder holder, int format, int w, int h) method
{
.
.
.
/*rotate the image by 90 degrees clockwise , in order to correctly displayed the image , images seem to be -90 degrees (counter clockwise) rotated
* I even tried setting it to p.setRotation(0); , but still no effect.
*/p.setRotation(90);
mCamera.setParameters(p);
.
.
.
}
But it has no effect, the image is still 90 counter clockwise, instead of the correct 0 degrees.
CameraPreview.java
Provides a SurfaceView in order to stream current images coming from the camera to the screen, so the uses can preview & see what the camera sees.
package com.ty.ownerspoc.barcode;
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;
import android.view.ViewGroup;
import android.hardware.Camera.CameraInfo;
/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private Context context;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
this.context = context;
// 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) {
}
}
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
}
Camera.Parameters p = mCamera.getParameters();
// get width & height of the SurfaceView
int SurfaceViewWidth = this.getWidth();
int SurfaceViewHeight = this.getHeight();
List<Size> sizes = p.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, SurfaceViewWidth, SurfaceViewHeight);
// set parameters
p.setPreviewSize(optimalSize.width, optimalSize.height);
/*rotate the image by 90 degrees clockwise , in order to correctly displayed the image , images seem to be -90 degrees (counter clockwise) rotated
* I even tried setting it to p.setRotation(0); , but still no effect.
*/
p.setRotation(90);
mCamera.setParameters(p);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d("CameraPreview , surfaceCreated() , orientation: ",
String.valueOf(e.getMessage()));
}
}// end surfaceChanged()
static Size getOptimalPreviewSize(List <Camera.Size>sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
final double MAX_DOWNSIZE = 1.5;
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 (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
double downsize = (double) size.width / w;
if (downsize > MAX_DOWNSIZE) {
//if the preview is a lot larger than our display surface ignore it
//reason - on some phones there is not enough heap available to show the larger preview sizes
continue;
}
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
//keep the max_downsize requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
double downsize = (double) size.width / w;
if (downsize > MAX_DOWNSIZE) {
continue;
}
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
//everything else failed, just take the closest match
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;
}
}//end class CameraPreview
Android activity (ScanVinFromBarcodeActivity):
Responsible for launching the camera & layout.
package com.ty.ownerspoc.barcode;
import java.io.IOException;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.MultiFormatReader; //found via import at compile time, however was found at run time
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;//found via import at compile time, however was found at run time
import com.google.zxing.Reader;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.PictureCallback;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.ty.ownerspoc.R;
public class ScanVinFromBarcodeActivity extends Activity {
private Camera globalCamera;
private int cameraId = 0;
private TextView VINtext = null;
private View scanButton = null;
// bitmap from camera
private Bitmap bmpOfTheImageFromCamera = null;
// global flag whether a camera has been detected
private boolean isThereACamera = false;
// surfaceView for preview object
private FrameLayout frameLayoutBarcodeScanner = null;
private CameraPreview newCameraPreview = null;
private SurfaceView surfaceViewBarcodeScanner = null;
/*
* This method , finds FEATURE_CAMERA, opens the camera, set parameters ,
* add CameraPreview to layout, set camera surface holder, start preview
*/
private void initializeGlobalCamera() {
try {
if (!getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA)) {
Toast.makeText(this, "No camera on this device",
Toast.LENGTH_LONG).show();
} else { // check for front camera ,and get the ID
cameraId = findFrontFacingCamera();
if (cameraId < 0) {
Toast.makeText(this, "No front facing camera found.",
Toast.LENGTH_LONG).show();
} else {
Log.d("ClassScanViewBarcodeActivity",
"camera was found , ID: " + cameraId);
// camera was found , set global camera flag to true
isThereACamera = true;
// OPEN
globalCamera = Camera.open(cameraId);
// pass surfaceView to CameraPreview
newCameraPreview = new CameraPreview(this, globalCamera);
// pass CameraPreview to Layout
frameLayoutBarcodeScanner.addView(newCameraPreview);
try {
globalCamera
.setPreviewDisplay(surfaceViewBarcodeScanner
.getHolder());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// PREVIEW
globalCamera.startPreview();
Log.d("ClassScanViewBarcodeActivity",
"camera opened & previewing");
}
}// end else ,check for front camera
}// end try
catch (Exception exc) {
// in case of exception release resources & cleanup
if (globalCamera != null) {
globalCamera.stopPreview();
globalCamera.setPreviewCallback(null);
globalCamera.release();
globalCamera = null;
}
Log.d("ClassScanViewBarcodeActivity initializeGlobalCamera() exception:",
exc.getMessage());
}// end catch
}
// onCreate, instantiates layouts & surfaceView used for video preview
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_barcode_vin_scanner);
Log.d("ClassScanViewBarcodeActivity", "onCreate ");
// create surfaceView for previewing of camera image
frameLayoutBarcodeScanner = (FrameLayout) findViewById(R.id.FrameLayoutForPreview);
surfaceViewBarcodeScanner = (SurfaceView) findViewById(R.id.surfaceViewBarcodeScanner);
initializeGlobalCamera();
// create text area & scan button
VINtext = (TextView) findViewById(R.id.mytext);
scanButton = findViewById(R.id.webbutton);
// on click listener, onClick take a picture
scanButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
// if true take a picture
if (isThereACamera) {
Log.d("ClassScanViewBarcodeActivity",
"setOnClickListener() isThereACamera: "
+ isThereACamera);
globalCamera.takePicture(null, null, jpegCallback);
globalCamera.stopPreview();
// wait 2 secs , than start preview again
Thread.sleep(2000);
globalCamera.startPreview();
}
}// end try
catch (Exception exc) {
// in case of exception release resources & cleanup
if (globalCamera != null) {
globalCamera.stopPreview();
globalCamera.setPreviewCallback(null);
globalCamera.release();
globalCamera = null;
}
Log.d("ClassScanViewBarcodeActivity setOnClickListener() exceprtion:",
exc.getMessage());
}// end catch
}// end on Click
});// end OnClickListener() implementation
}// end onCreate
#Override
protected void onResume() {
Log.d("ClassScanViewBarcodeActivity, onResume() globalCamera:",
String.valueOf(globalCamera));
if (globalCamera != null) {
// START PREVIEW
globalCamera.startPreview();
} else {
initializeGlobalCamera();
}
super.onResume();
}
#Override
protected void onStop() {
if (globalCamera != null) {
globalCamera.stopPreview();
globalCamera.setPreviewCallback(null);
globalCamera.release();
globalCamera = null;
}
super.onStop();
}
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] imgData, Camera camera) {
try {
// get the bitmap from camera imageData
bmpOfTheImageFromCamera = BitmapFactory.decodeByteArray(
imgData, 0, imgData.length);
BinaryBitmap bitmap = null;
if (bmpOfTheImageFromCamera != null) {
// convert bitmap to binary bitmap
bitmap = cameraBytesToBinaryBitmap(bmpOfTheImageFromCamera);
if (bitmap != null) {
// decode the VIN
String VIN = decodeBitmapToString(bitmap);
Log.d("***ClassScanViewBarcodeActivity ,onPictureTaken(): VIN ",
VIN);
VINtext.setText(VIN);
} else {
Log.d("ClassScanViewBarcodeActivity ,onPictureTaken(): bitmap=",
String.valueOf(bitmap));
}
} else {
Log.d("ClassScanViewBarcodeActivity , onPictureTaken(): bmpOfTheImageFromCamera = ",
String.valueOf(bmpOfTheImageFromCamera));
}
}// end try
catch (Exception exc) {
exc.getMessage();
Log.d("ClassScanViewBarcodeActivity , scanButton.setOnClickListener(): exception = ",
exc.getMessage());
}
}// end onPictureTaken()
};// jpegCallback implementation
private int findFrontFacingCamera() {
int cameraId = -1;
// Search for the front facing camera
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) {
Log.d("ClassScanViewBarcodeActivity , findFrontFacingCamera(): ",
"Camera found");
cameraId = i;
break;
}
}
return cameraId;
}// end findFrontFacingCamera()
#Override
protected void onPause() {
if (globalCamera != null) {
globalCamera.stopPreview();
globalCamera.setPreviewCallback(null);
globalCamera.release();
globalCamera = null;
}
super.onPause();
}// end onPause()
public String decodeBitmapToString(BinaryBitmap bitmap) {
Reader reader = null;
Result result = null;
String textResult = null;
try {
reader = new MultiFormatReader();
if (bitmap != null) {
result = reader.decode(bitmap);
if (result != null) {
textResult = result.getText();
} else {
Log.d("ClassScanViewBarcodeActivity , String decodeBitmapToString (BinaryBitmap bitmap): result = ",
String.valueOf(result));
}
} else {
Log.d("ClassScanViewBarcodeActivity , String decodeBitmapToString (BinaryBitmap bitmap): bitmap = ",
String.valueOf(bitmap));
}
/*
* byte[] rawBytes = result.getRawBytes(); BarcodeFormat format =
* result.getBarcodeFormat(); ResultPoint[] points =
* result.getResultPoints();
*/
} catch (NotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ChecksumException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return textResult;
}// end decodeBitmapToString (BinaryBitmap bitmap)
public BinaryBitmap cameraBytesToBinaryBitmap(Bitmap bitmap) {
BinaryBitmap binaryBitmap = null;
if (bitmap != null) {
int[] pixels = new int[bitmap.getHeight() * bitmap.getWidth()];
bitmap.getPixels(pixels, 0, 0, bitmap.getWidth() - 1,
bitmap.getHeight() - 1, bitmap.getWidth(),
bitmap.getHeight());
RGBLuminanceSource source = new RGBLuminanceSource(
bitmap.getWidth(), bitmap.getHeight(), pixels);
HybridBinarizer bh = new HybridBinarizer(source);
binaryBitmap = new BinaryBitmap(bh);
} else {
Log.d("ClassScanViewBarcodeActivity , cameraBytesToBinaryBitmap (Bitmap bitmap): bitmap = ",
String.valueOf(bitmap));
}
return binaryBitmap;
}
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
/*
* The method getScreenOrientation() return screen orientation either
* landscape or portrait. IF width < height , than orientation = portrait,
* ELSE landscape For backwards compatibility we use to methods to detect
* the orientation. The first method is for API versions prior to 13 or
* HONEYCOMB.
*/
public int getScreenOrientation() {
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
// if API version less than 13
Display getOrient = getWindowManager().getDefaultDisplay();
int orientation = Configuration.ORIENTATION_UNDEFINED;
if (currentapiVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
// Do something for API version less than HONEYCOMB
if (getOrient.getWidth() == getOrient.getHeight()) {
orientation = Configuration.ORIENTATION_SQUARE;
} else {
if (getOrient.getWidth() < getOrient.getHeight()) {
orientation = Configuration.ORIENTATION_PORTRAIT;
} else {
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
}
} else {
// Do something for API version greater or equal to HONEYCOMB
Point size = new Point();
this.getWindowManager().getDefaultDisplay().getSize(size);
int width = size.x;
int height = size.y;
if (width < height) {
orientation = Configuration.ORIENTATION_PORTRAIT;
} else {
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
}
return orientation;
}// end getScreenOrientation()
}// end class activity
layout for the activity "ScanVinFromBarcodeActivity" , activity_barcode_vin_scanner.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="20dip" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:padding="20dip"
android:text="#string/decode_label"
android:textColor="#color/mbackground1" />
<TextView
android:id="#+id/mytext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/mbackground2"
android:gravity="center_horizontal"
android:padding="20dip"
android:textColor="#color/mytextcolor" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:padding="20dip"
android:text="#string/continue_label"
android:textColor="#color/mytextcolor" />
<Button
android:id="#+id/webbutton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/web_button"
android:textColor="#color/mytextcolor" />
<FrameLayout
android:id="#+id/FrameLayoutForPreview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<SurfaceView
android:id="#+id/surfaceViewBarcodeScanner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
</LinearLayout>
Any help will be appreciated.
Thanks
If you call mCamera.setDisplayOrientation(90) before you call setPreviewDisplay in your surfaceCreated method this should fix the SurfaceView orientation but the image rotation will still be wrong.
I'm currently working on a Nexus 7 and Galaxy S3 and calling setRotation(270) on the camera parameters with the Nexus (front-facing camera only) fixes the image rotation. This setter seems to have no effect on the S3.
What I'm doing at the moment is rotating the image itself 90 degrees in the onPictureTaken handler, for a front-facing camera the rotation needs to be anti-clockwise (-90):
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bmpWidth, bmpHeight, matrix, true);
This works for the two devices I mentioned, but I am concerned as to how this will behave on other devices.

Android Camera setDisplayOrientation does not work

i am working camera project in android.my problem is camera setDisplayOrientation method is not working and my camera preview on surface always landscape.i want to expected portrait camera preview on SurfaceView. I am using Samsung galaxy y (Android 2.3.5) and my activity code shown below:
import java.io.IOException;
import android.app.Activity;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
public class AndroidCamera extends Activity implements SurfaceHolder.Callback{
Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
boolean previewing = false;;
String stringPath = "/sdcard/samplevideo.3gp";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonStartCameraPreview = (Button)findViewById(R.id.startcamerapreview);
Button buttonStopCameraPreview = (Button)findViewById(R.id.stopcamerapreview);
getWindow().setFormat(PixelFormat.UNKNOWN);
surfaceView = (SurfaceView)findViewById(R.id.surfaceview);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
buttonStartCameraPreview.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(!previewing){
camera = Camera.open();
if (camera != null){
try {
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
previewing = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}});
buttonStopCameraPreview.setOnClickListener(new Button.OnClickListener(){
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(camera != null && previewing){
camera.stopPreview();
camera.release();
camera = null;
previewing = false;
}
}});
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
}
my problem shown blow figure:
Any one can help with any code or tutorial links and thanks for spending valuable your time
Finally i got solution and find camera preview surface view following code:
import java.io.IOException;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private static boolean DEBUGGING = true;
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;
protected List<Camera.Size> mPreviewSizeList;
protected List<Camera.Size> mPictureSizeList;
protected Camera.Size mPreviewSize;
protected Camera.Size mPictureSize;
public CameraPreview(Context context, Camera camera) {
super(context);
mActivity=(Activity)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("CameraView", "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
try {
Camera.Parameters cameraParams = mCamera.getParameters();
boolean portrait = isPortrait();
configureCameraParameters(cameraParams, portrait);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d("CameraView", "Error starting camera preview: " + e.getMessage());
}
}
public void onPause() {
mCamera.release();
mCamera = null;
}
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);
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);
}
public boolean isPortrait() {
return (mActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
}
}
It's need minimum sdk 2.3 or higher
if you want to rotate the preview output, try this:
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
if (isPreviewRunning)
{
mCamera.stopPreview();
}
Parameters parameters = mCamera.getParameters();
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
if(display.getRotation() == Surface.ROTATION_0)
{
parameters.setPreviewSize(height, width);
mCamera.setDisplayOrientation(90);
}
if(display.getRotation() == Surface.ROTATION_90)
{
parameters.setPreviewSize(width, height);
}
if(display.getRotation() == Surface.ROTATION_180)
{
parameters.setPreviewSize(height, width);
}
if(display.getRotation() == Surface.ROTATION_270)
{
parameters.setPreviewSize(width, height);
mCamera.setDisplayOrientation(180);
}
mCamera.setParameters(parameters);
previewCamera();
}
For lower API levels you could use:
private void setCameraDisplayOrientationAPI8(){
//Sets the camera right Orientation.
//Special void for API 8 build.
//This void should be called before calling camera.setParameters(cameraParameters).
if (activeActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
{
camera.setDisplayOrientation(90);
}
if (activeActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
{
camera.setDisplayOrientation(180);
}
}
and just call setCameraDisplayOrientationAPI8(); on your surfaceChanged func.
plus:
private void setCameraDisplayOrientation() {
//Sets the camera right Orientation.
//IMPORTANT!! This code is available only for API Level 9 build or greater.
if (mApiLvl<9){
Log.d(TAG, "setCameraDisplayOrientation ERROR: This code is available only for API Level 9 build or greater.");
return;
}
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraIndex, info);
int rotation = activeActivity.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);
}
hope this helps.
Also, check if the "Auto-rotate Screen" option is checked in the phone Settings (Settings > Dislay or Screen - depends on the android version).
It took me quite a while till a figured it out. If it's not checked, the orientation of the camera in the app may be ignored.

Android camera preview look strange

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;
}

Android Camera recording video but plays upside down

I record a video using the below code and it records perfectly, but when it plays the video, it plays it upside down.
I tried settings mrec.setOrientationHint(180) before mrec.prepare(); but it was useless. Any hints?
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Activity;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
/**
* #author SANA HASSAN
*/
public class CameraSurfaceView extends Activity {
private Preview mPreview;
private MediaRecorder mrec = new MediaRecorder();
private int cameraId = 0;
private Camera mCamera;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
mPreview = new Preview(this);
setContentView(mPreview);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, 0, 0, "Start");
menu.add(0, 1, 0, "Stop");
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 0:
try {
startRecording();
}
catch (Exception e) {
e.printStackTrace();
mrec.release();
}
break;
case 1:
mrec.stop();
mrec.release();
mrec = null;
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
protected void startRecording() throws IOException {
mrec = new MediaRecorder();
mrec.setCamera(mCamera);
mCamera.unlock();
File directory = new File(Environment.getExternalStorageDirectory()+"/NICUVideos");
directory.mkdirs();
mrec.setAudioSource( MediaRecorder.AudioSource.MIC);
mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mrec.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mrec.setOutputFile(Environment.getExternalStorageDirectory()+"/NICUVideos/"+System.currentTimeMillis()+".mp4");
mrec.setPreviewDisplay(mPreview.getHolder().getSurface());
mrec.setVideoSize(640, 480);
Method[] methods = mrec.getClass().getMethods();
for (Method method: methods){
try{
if(method.getName().equals("setAudioEncodingBitRate")){
method.invoke(mrec, 12200);
}
else if(method.getName().equals("setVideoEncodingBitRate")){
method.invoke(mrec, 800000);
}
else if(method.getName().equals("setAudioSamplingRate")){
method.invoke(mrec, 8000);
}
else if(method.getName().equals("setVideoFrameRate")){
method.invoke(mrec, 20);
}
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
}
mrec.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mrec.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mrec.setMaxDuration(60000); // 60 seconds
mrec.setMaxFileSize(10000000); // Approximately 10 megabytes
mrec.prepare();
mrec.start();
}
protected void stopRecording() {
mrec.stop();
mrec.release();
mCamera.release();
}
class Preview extends SurfaceView implements SurfaceHolder.Callback {
SurfaceHolder mHolder;
Activity activity;
Preview(Activity activity) {
super(activity);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
Camera.CameraInfo info=new Camera.CameraInfo();
for (int i=0; i < Camera.getNumberOfCameras(); i++) {
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
mCamera=Camera.open(i);
cameraId = i;
}
}
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
mCamera.release();
mCamera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
setCameraDisplayOrientation(mCamera);
mCamera.startPreview();
}
public void setCameraDisplayOrientation(Camera camera) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = CameraSurfaceView.this.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;
}
Log.d(Vars.TAG, "Result = "+result);
camera.setDisplayOrientation(result);
}
}
}
This problem is due to Android handling rotation by just setting some metadata instead of actually rotating the video, and some playback software then ignoring that setting.
As noted in the docs:
Note that some video players may choose to ignore the compostion matrix in a video during playback.
Your options are to either use different playback software that understands the metadata being set, or to re-encode the video after it's been recorded to the correct orientation. It's not clear from your description which of those would be the better solution in your case.
This should be called before the mrec.prepare(); method
setOrientationHint(degrees);
Link
EDIT:
Try mCamera.setDisplayOrientation(degrees);
0 for landscape
90 for portrait
180 & 270 don't work very well and give weird results.
Some older players and encoders do not interpret this flag which is why the video plays upside down.
I know your issue,
Video use Media Recorder from Camera, so you need rotate Media Recorder. use below codes should be fixed your issue.
/**
*
* #param mMediaRecorder
* #return
*/
public static MediaRecorder rotateBackVideo(MediaRecorder mMediaRecorder) {
/**
* Define Orientation of video in here,
* if in portrait mode, use value = 90,
* if in landscape mode, use value = 0
*/
switch (CustomCamera.current_orientation) {
case 0:
mMediaRecorder.setOrientationHint(90);
break;
case 90:
mMediaRecorder.setOrientationHint(180);
break;
case 180:
mMediaRecorder.setOrientationHint(270);
break;
case 270:
mMediaRecorder.setOrientationHint(0);
break;
}
return mMediaRecorder;
}
Should add before prepare() method :
// Step 5: Set the preview output
/**
* Define Orientation of image in here,
* if in portrait mode, use value = 90,
* if in landscape mode, use value = 0
*/
CustomCamera.mMediaRecorder = Utils.rotateBackVideo(CustomCamera.mMediaRecorder);
CustomCamera.mMediaRecorder.setPreviewDisplay(mCameraPreview.getHolder().getSurface());
Thank you
I have the same problem, I note that camera preview orientation angle and recording video angle aren't the same.
So I use this method for change orientation on video recording:
public static int getVideoOrientationAngle(Activity activity, int cameraId) { //The param cameraId is the number of the camera.
int angle;
Display display = activity.getWindowManager().getDefaultDisplay();
int degrees = display.getRotation();
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
switch (degrees) {
case Surface.ROTATION_0:
angle = 90;
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;
}
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
angle = (angle + 180) % 360;
return angle;
}
And that for change orientation on camera preview:
public 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;
}
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;
}
Note that's important to know if the camera is front or back.
Use OrientationEventListener and track rotation value when device is rotated code here.This code apply rotation to camera but for recording you need apply rotation to MediaRecorder.When you start recording just mMediaRecorder.setOrientationHint(rotation) before mMediaRecorder.prepare(). This solve my problem.
Finally I have found out that Motorola phones have problem in playing the video which is recorded in portrait mode.
In order to overcome the rotation of the video, the best solution I have adopted was to upload the video to the server and run ffmpeg on using the command ffmpeg -i input.mp4 -c:v mpeg4 -c:a copy -c:s copy -vf "transpose=2" output.mp4
If you feel there was another way, please do let me know.
one more solution is to rotate your activity so that its orientation is the same as sensor orientation. That is, landscape for back camera and upside-down portrait for front camera. This btw will not fix mirror effect for the front camera. One more difficulty is that you will have to implement your UI in those rotated activities in a way to follow the activity orientation.
rotate your MediaRecorder like below corresponding the degree you used in Camera display orientation for front facing camera video recording
Display display = ((WindowManager)getContext().getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
parameters.setPreviewSize(height, width);
if(display.getRotation() == Surface.ROTATION_0)
{
mCamera.setDisplayOrientation(90);
mMediaRecorder.setOrientationHint(270);
}
if(display.getRotation() == Surface.ROTATION_90)
{
mMediaRecorder.setOrientationHint(180);
}
if(display.getRotation() == Surface.ROTATION_180)
{
mMediaRecorder.setOrientationHint(270);
}
if(display.getRotation() == Surface.ROTATION_270)
{
mCamera.setDisplayOrientation(180);
mMediaRecorder.setOrientationHint(0);
}
Here is the code for custom portrait camera, will set the correct rotation of picture and video:
private OrientationEventListener orientationEventListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
orientationEventListener = new OrientationEventListener(this) {
#Override
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWN) return;
flashButton.setRotation(-(orientation));
cameraButton.setRotation(-(orientation));
if (camera != null) {
Parameters parameters = camera.getParameters();
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(selectedCamera, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
parameters.setRotation(rotation);
if (!isRecording) {
mediaRecorder.setOrientationHint(rotation);
}
camera.setParameters(parameters);
}
}
};
}
#Override
protected void onResume() {
super.onResume();
//...
orientationEventListener.enable();
}
#Override
protected void onPause() {
super.onPause();
orientationEventListener.disable();
//...
}
Teste with portrait orientation. Remeber to put it in your manifest to test code. I dont know if work in landscape.
<activity android:name=".activities.CameraActivity"
android:screenOrientation="portrait">
for portrait mode set your mediaRecorder.setOrientationHint(90); degree is same as your camera orientation myCamera.setDisplayOrientation(90);

Categories

Resources