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,
- add check for
camera != null
- only call
camera.setDisplayOrientation(result)
(or perform any heavy-lifting) ifresult
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
Android:Fill Spinner from Java Code Programmatically
How to Get the Google Username on Android
Query If Android Database Exists!
The Process of the Service Is Killed After the Application Is Removed from the Application Tray
Add a Search Filter on Recyclerview with Cards
Load an Image from Assets Folder
How to Give Hexagon Shape to Imageview
Http Request in Android with Kotlin
How to Execute the Dex File in Android with Command
Drawable-Hdpi, Drawable-Mdpi, Drawable-Ldpi Android
How to Programmatically Enable/Disable Accessibility Service in Android
List of Files in Assets Folder and Its Subfolders
Handling Buttons Inside Android Notifications
Android: Unable to Instantiate Activity/Classnotfoundexception