Rotating Phone Quickly 180 Degrees, Camera Preview Turns Upside Down

Rotating phone quickly 180 degrees, camera preview turns upside down

You can use OrientationEventListener to trigger recalculation of camera rotation.

Add to your activity:

private OrientationEventListener orientationListener = null;

to onCreate():

orientationListener = new OrientationEventListener(this) {
public void onOrientationChanged(int orientation) {
setCameraDisplayOrientation(CustomCameraActivity.this, cameraId, camera);
}
};

to surfaceCreated():

orientationListener.enable();

to surfaceDestroyed():

orientationListener.disable();

Now, it almost works. To make setCameraDisplayOrientation() more robust,

  1. add check for camera != null
  2. only call camera.setDisplayOrientation(result) (or perform any heavy-lifting) if result changed since last time the function was called.

Quick 180 rotation of iOS Device results in the camera viewing upside-down

I had the same issue before here what solved my issue.

I declared a global variable:

@interface YourViewController ()
{
...
UIDevice *iOSDevice;
}

..

@end

Under implementation (.m file) i declared NSNotification observer under -viewWillAppear like:

@implementation YourViewController

-(void)viewWillAppear:(BOOL)animated
{
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]];

}

-(void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}

- (void)orientationChanged:(NSNotification *)notification
{
iOSDevice = notification.object;

previewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation];

//or

[self setAutoVideoConnectionOrientation:YES];

}

I made a function that returns the orientation of the copied current device like:

Take a loot at my -interfaceOrientationToVideoOrientation method, it converts the iOSDevice.orientation into AVCaptureVideoOrientation same with what you have there..


(In my case i needed this functions below, but take a look at it might be useful to you for some reason)

- (AVCaptureVideoOrientation)interfaceOrientationToVideoOrientation
{
switch (iOSDevice.orientation) {

case UIInterfaceOrientationPortraitUpsideDown:

return AVCaptureVideoOrientationPortraitUpsideDown;

case UIInterfaceOrientationLandscapeLeft:

return AVCaptureVideoOrientationLandscapeLeft;

case UIInterfaceOrientationLandscapeRight:

return AVCaptureVideoOrientationLandscapeRight;

default:
case UIDeviceOrientationPortrait:
return AVCaptureVideoOrientationPortrait;
}
}

- (AVCaptureConnection *)setAutoVideoConnectionOrientation:(BOOL)status
{
AVCaptureConnection *videoConnection = nil;

//This is for me
//for (AVCaptureConnection *connection in stillImageOutput.connections) {

//This might be for you
for (AVCaptureConnection *connection in previewLayer.connection) {

for (AVCaptureInputPort *port in [connection inputPorts])
{
if ([[port mediaType] isEqual:AVMediaTypeVideo])
{
videoConnection = connection;

if (status == YES)
{
[videoConnection setVideoOrientation:[self interfaceOrientationToVideoOrientation]];
}
else
{
[videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
}
}
if (videoConnection)
{
break;
}
}
}
return videoConnection;
}

Edit

For default orientation: You need to check the "current" orientation.

- (void)viewDidLoad
{
[super viewDidLoad];

// assuming you finish setting the `previewLayer`

..
// after all of that code, when the view is ready for displaying
// if you implemented this approach the best thing to do is:

// set this
iOSDevice = [UIDevice currentDevice];

// then call
previewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation];
// to update the `previewLayer.connection.videoOrientation ` for default orientation

}

Note:

Using NSNotificationCenter let the rotation of the device to be settled first before triggered..

Hope this have help you..

Camera Preview upside down

I would use matrix.setRotate().

matrix.postRotate() adds on the rotate every time it gets called. Angles go from 270 -> 540 -> 810 -> 1080 -> 1350 -> etc.

matrix.setRotate() would always set it to 270.

Rotation 180 degrees android doesn't work properly

You need to get the camera's supporting parameters like this:

Camera.Parameters parameters = camera.getParameters();

and add this line before before mCamera.setDisplayOrientation(int);

parameters.setRotation(int);

for example:

if(display.getRotation() == Surface.ROTATION_0){//0
parameters.setRotation(90);
mCamera.setDisplayOrientation(90);
}else if(display.getRotation() == Surface.ROTATION_90){//1
parameters.setRotation(0);
mCamera.setDisplayOrientation(0);
}else if(display.getRotation() == Surface.ROTATION_180){//2
parameters.setRotation(270);
mCamera.setDisplayOrientation(270);
}else if(display.getRotation() == Surface.ROTATION_270){//3
parameters.setRotation(180);
mCamera.setDisplayOrientation(180);
}

hope this answers your question

EDIT

The above code needs to be present also in onResume() method because each time orientation is changed onDestroy() is called and then onCreate() is called so onResume() needs to have this piece of code as well as onCreate().

EDIT 2

Take a look at OrientationEventListener

Further more take a look at this question for hint regarding OrientationEventListener

Hope you will find this answer a little bit useful.

How to detect screen rotation through 180 degrees from landscape to landscape orientation?

OrientationEventlistener won't work when the device isn't rotating/moving.

I find display listener is a better way to detect the change.

     DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {
android.util.Log.i(TAG, "Display #" + displayId + " added.");
}

@Override
public void onDisplayChanged(int displayId) {
android.util.Log.i(TAG, "Display #" + displayId + " changed.");
}

@Override
public void onDisplayRemoved(int displayId) {
android.util.Log.i(TAG, "Display #" + displayId + " removed.");
}
};
DisplayManager displayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
displayManager.registerDisplayListener(mDisplayListener, UIThreadHandler);


Related Topics



Leave a reply



Submit