Android - Camera Preview Is Sideways

Android - Camera preview is sideways

This issue appeared to start out as a bug with certain hardware see here but can be overcome by using the call to mCamera.setDisplayOrientation(degrees) available in API 8. So this is how I implement it:

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

And the previewCamera method :

public void previewCamera() {
try {
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
isPreviewRunning = true;
} catch(Exception e) {
Log.d(APP_CLASS, "Cannot start preview", e);
}
}

This was on an HTC Desire and I had to initially put in logging statements in each of the rotation checks to say what the rotation was and then debugged on the device and watched the logCat output while I rotated the device. For the HTC Desire, 0 was the phone as you would have expected (portrait), 90 degrees was turning the phone 90 degrees COUNTER-CLOCKWISE (I had assumed it would have been clockwise). In the code you'll see I didn't need to do any display rotation when the phone was at 90 or 180 degrees - the device seemed to handle this itself. Only one point not working properly: The 270 degree rotation is when you turn the device 90 degrees clockwise and the display rotation counters that ok but if you rotate the device 270 degrees counter-clockwise, it doesn't appear to compensate it properly.

P.S. Note the swapover of width and height in the appropriate rotations.

Camera automatically get rotated by 90 degree in portrait mode

On the surfaceView which holds the Camera instance, you have to implement few methods. one of them is surfaceChanged. in that method you should update the orientation as follow:

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {

...
this.setCameraDisplayOrientation(this.cameraId, this.mCamera);
...
}

And the implementation:

   /**
* Calling this method makes the camera image show in the same orientation as the display.
* NOTE: This method is not allowed to be called during preview.
*
* @param cameraId
* @param camera
*/
@SuppressLint("NewApi")
public void setCameraDisplayOrientation(int cameraId, android.hardware.Camera camera) {
int rotation = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).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 (Utils.hasGingerbread()) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
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;
}
} else {
// on API 8 and lower devices
if (context.getResources().getConfiguration().orientation !=Configuration.ORIENTATION_LANDSCAPE) {
result = 90;
} else {
result = 0;
}
}
try {
camera.setDisplayOrientation(result);
} catch (Exception e) {
// may fail on old OS versions. ignore it.
e.printStackTrace();
}
}

Android: retaining camera preview on orientation change while other views can rotate

If your manifest does not declare that the activity handles orientation changes, and is not locked to a single orientation, then rotation of the device will cause the whole activity to get unloaded and reloaded again. Isn't this what you experience now?

If you specify android:configChanges="orientation|screenSize" for your activity, then the user experience will be much smoother. But still, you cannot keep the camera preview "intact" after such rotation; the layout will be rebuilt.

Finally, the approach of the stock camera app is to set fixed (usually landscape) activity orientation and fake the portrait orientation by changing the buttons and other UI elements. But if you look for the system notifications or navigation (soft) buttons on the bottom, you will understand that actually device is locked in landscape, only controls are redrawn. You will also notice that camera apps avoid standard text widgets, because such widgets cannot be easily rotated.

By the way, there is another misunderstanding in your question. If you want to store the picture as portrait, you will need (or not need) manual rotation of the JPEG regardless of your activity orientation. On most devices, camera can only produce landscape JPEG files. Camera API includes setRotation() method, but usually, this only sets an EXIF flag in the JPEG header. Not all image viewers respect this flag. You may need manual rotation of the image if you don't want to compromize.

Android: Camera preview orientation in portrait mode

To force portrait orientation:

set android:screenOrientation="portrait" in your AndroidManifest.xml and call camera.setDisplayOrientation(90); before calling camera.startPreview();

I have not tested on the GS2 but it works on every phone I have tested on.

Note: setDisplayOrientation was added in API Level 8

Android: Encoded Camera Preview Frames always in landscape. How to rotate?

The camera Activities in Grafika render every frame twice: once for the display, and once for encoding. You want to do the same thing, but throw in a rotation (and make an appropriate adjustment to the MediaCodec / MediaRecorder configuration, i.e. 720x1280 vs. 1280x720).

For example, consider the drawFrame() method in ContinuousCapture. It selects the SurfaceView's EGLSurface, draws, then switches to the video encoder's EGLSurface and calls the same draw method. It even throws in a call to drawExtra() just to show that it can.

In both cases you're just rendering GLES onto an EGLSurface, and the EGLSurface gets its dimensions from the underlying Surface, which either came from SurfaceView or MediaCodec. If you modify FullFrameRect#drawFrame() to take a matrix argument, and pass in a rotation matrix in place of the identity matrix it currently uses, you should get the result you want.



Related Topics



Leave a reply



Submit