32

With android.hardware.Camera, in order to have the camera output appropriately track the device movement, we need to hook up an OrientationEventListener to the setDisplayOrientation() method on Camera. That way, as the user twists the device around, we can keep what is "up" on the camera preview in sync with what is "up" in the real world. This is particularly true for rotating the device around the Y axis (i.e., flipping from landscape to reverse-landscape or back).

For most orientation changes, the android.hardware.camera2 API seems to "just work". However, for that Y-axis rotation (landscape -> reverse-landscape or vice versa), the camera preview winds up being inverted.

What is the equivalent of calling setDisplayOrientation() on Camera for the Camera2 API, so we can handle this scenario?

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • it seems for camera2 and android 6.0 (tested on emulators) `characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)` returns always **270**, and that's why the preview is inverted, when it returns **90** then preview is ok, so I guess we should make manual transformation for SurfaceView if camera sensor orientation is 270 to fix preview – user924 Sep 05 '20 at 10:59
  • @user924: "tested on emulators" -- relying on emulators for evaluating the behavior of camera APIs is not wise, IMHO. – CommonsWare Sep 05 '20 at 11:26
  • Yeah, mb. I just don't have a real device, like Nexus 5X, which returns 270 degrees for camera sensor orientation, but I think emulator and such devices behave the same, both have upside down preview when using SurfaceView. Did you find any solution? We could use TextureView and apply matrix based on camera orientation value, but I would like to use SurfaceView and I didn't find any solution for it. I hope TextureView isn't the only solution – user924 Sep 05 '20 at 11:33

4 Answers4

8

As you've noticed, this is supposed to "just work" for SurfaceView on the camera2 API.

As such, there's no equivalent of setDisplayOrientation().

We haven't heard of this issue before now, so a few questions:

  1. Do you have your app locked to landscape, or are you allowing orientation changes?
  2. Do you handle your own orientation changes, or are you having the framework tear down and restart your app when orientation changes?
  3. Do you trigger any sort of re-layout when the 180-degree rotation occurs, for example to adjust where the shutter button is?
Ragunath Jawahar
  • 19,513
  • 22
  • 110
  • 155
Eddy Talvala
  • 17,243
  • 2
  • 42
  • 47
  • 1
    The problem of Y flip is rooted in the orientation handling on Android. Normally, we can simply follow the orientation change events. But unfortunately no orientation change is recognized when the device is quickly rotated from landscape to reverse landscape (without going through portrait). I believe this is s big in the system. We could work around it with OrientationEventListener, but this workaround is not useful with camera2 – Alex Cohn Nov 03 '15 at 05:17
  • 1
    See *[Rotating phone quickly 180 degrees, camera preview turns upside down](http://stackoverflow.com/questions/19532599/rotating-phone-quickly-180-degrees-camera-preview-turns-upside-down)* and the linked questions – Alex Cohn Nov 03 '15 at 07:56
  • 1) Allowing orientation changes 2) Stock Android configuration change behavior (activity destroy/recreate) 3) We can't tell a 180-degree rotation occurs with any accuracy, so no, I am not doing anything for that scenario. See Alex Cohn's comments. You can try this yourself by running either the `demo` or `demo-playground` apps from [my CWAC-Cam2 library's repository](https://github.com/commonsguy/cwac-cam2). – CommonsWare Nov 03 '15 at 11:26
  • That's fairly odd -a full activity destroy/recreate would really be expected to work. In our internal test app, which handles configuration changes on its own, there are no issues with the 180-degree flip and a SurfaceView. I don't have an app handy to test the activity destroy/recreate case, since that's jankier from a camera perspective (have to close and reopen the camera device). Can you provide the output of 'adb shell dumpsys SurfaceFlinger' for the working and nonworking cases? – Eddy Talvala Nov 06 '15 at 23:36
  • @EddyTalvala: "a full activity destroy/recreate would really be expected to work" -- a 180-degree flip around the Y axis *doesn't* cause a configuration change, which is part of the point here. I am not exactly certain what you are considering "the working and nonworking cases", but I have uploaded two `dumpsys` output files and attached them to [my issue for this](https://github.com/commonsguy/cwac-cam2/issues/24#issuecomment-154583666). One is the N5 in landscape, the other is the same N5 rotated 180 degrees around the Y axis (i.e., not hitting portrait) to reverse landscape. – CommonsWare Nov 07 '15 at 00:16
  • @EddyTalvala: BTW, Google's [own sample app](https://github.com/googlesamples/android-Camera2Basic) demonstrates this same behavior, so it's not something unique to my code. Somebody filed [a related issue for this](https://github.com/googlesamples/android-Camera2Basic/issues/5) on that repo a while back. Ironically, I can't reproduce this problem (in Google's code or mine) with a 180-degree flip from portrait to reverse-portrait, only landscape to reverse-landscape. – CommonsWare Nov 07 '15 at 00:21
  • 1
    Thanks, we'll try to take a look shortly, and see where the issue might be. – Eddy Talvala Nov 08 '15 at 22:22
  • 1
    @EddyTalvala: Would it help if I filed a formal issue for this? With the current edition of [Google's sample app](https://github.com/googlesamples/android-Camera2Basic), this is reproducible on a Google Nexus 5, a Google Nexus 5X, a Google Nexus 6P, a Google Nexus 7 (2013), and a Google Nexus 9, all running Android 6.0. If you fix the sample to not try using `checkSelfPermission()` on older devices, the problem can be reproduced on a Google Nexus 4 running Android 5.1. – CommonsWare Dec 07 '15 at 18:40
  • Feel free to file an issue at b.android.com, certainly. – Eddy Talvala Dec 10 '15 at 22:43
  • @EddyTalvala: My apologies for the delay on this -- either I didn't get the notification that you had commented or I lost it when processing other notifications. I just filed [an issue about this](https://code.google.com/p/android/issues/detail?id=198411). – CommonsWare Jan 06 '16 at 17:28
  • Ragunath, you said 'this is supposed "just work" for SurfaceView'. Please explain, what you mean by "this." That now the camera image magically tracks the device orientation without an angle offset (in degrees) given the camera2 APIs? – BoiseBaked Jul 13 '16 at 20:31
  • Hi @Ragunath, can you please elaborate what should happen or what seems to be a problem, if you do some of the things that you mentioned as your question to the original poster. I mean what is the problem if you have your app locked to portrait mode, and similar for other 2 questions. Thanks in advance. – aleksamarkoni Dec 12 '17 at 22:13
  • @EddyTalvala this samples also shows preview upside down if camera sensor orientation is 270 https://github.com/android/camera-samples/tree/master/Camera2Basic You can try to add Pixel Emulator with 6.0 (23 API) x86 Image to get such camera sensor orientation, other android images returns 90 for camera sensor orientation. Also a eal device Nexus5X returns 270 – user924 Sep 05 '20 at 10:51
  • I have this issue also for headunits (car radio) devices, for usb external cameras with sensor orientation 0 – user924 Sep 15 '22 at 11:56
  • https://issuetracker.google.com/issues/37076769#comment8 – user924 Sep 15 '22 at 12:08
0

There is none.

It does not "just work" if display orientation is swapped compared to sensor orientation (on most devices this is the case in portrait mode) because you have to set an aspect ratio < 1 for your preview surface that camera2 cannot map to a fitting output size. Solution:

Andi
  • 457
  • 3
  • 19
0

use this CaptureRequest JPEG_ORIENTATION to set your display orientation

captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, 90)

Moses Liao GZ
  • 1,556
  • 5
  • 20
  • 45
-1

use the formula below to get device rotation.

private int getOrientation(int rotation) {
    return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
}

SensorOrientation is a field assigned from

characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) 

Solution suggested by google engineer: yaraki

https://github.com/googlesamples/android-Camera2Basic/issues/24

  • 4
    This does not answer the question. The question is how to replace `setDeviceOrientation()`, not how to calculate the device orientation. – CommonsWare Mar 15 '16 at 11:20