Why in the portrait screen orientation the camera surface is rotated by -90 degrees "90 degrees anticlockwise". I want the camera preview to be normal regardless of the screen orientation. How can I achieve that.
Did you tried this:
mCam.setDisplayOrientation(90); use it inside surfaceChanged(...)
setDisplayOrientation
Set the clockwise rotation of preview display in degrees. This affects the preview frames and the picture displayed after snapshot. This method is useful for portrait mode applications. Note that preview display of front-facing cameras is flipped horizontally before the rotation, that is, the image is reflected along the central vertical axis of the camera sensor. So the users can see themselves as looking into a mirror.
This does not affect the order of byte array passed in onPreviewFrame(byte[], Camera), JPEG pictures, or recorded videos. This method is not allowed to be called during preview.
Related
The precondition is we have to let Activity rotate follow the system orientation, so i add following code to the AndroidManifest.xml:
android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode"
android:screenOrientation="sensor"
And set the rotationAnimation to ROTATION_ANIMATION_SEAMLESS.
WindowManager.LayoutParams windowAttributes = getWindow().getAttributes(); windowAttributes.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; getWindow().setAttributes(windowAttributes);
I reset the correct glViewport, projection matrix and model matrix in surfaceChanged(),the proplem is that serveral frames looks weired while change the device orientation, but after rotation is complete, all frames look good.
This image shows what's going on:
It tried to reset viewport and matrix while onConfigurationChanged() is invoked, but it doesn't work.
I want the frames look seamless while change the device orientation, just as the Pixels' camera APP did.
It's simple: it's not possibile to avoid this completly.
You could let the SurfaceView invisible while rotation is not completed, but the Surface cannot renders not-yet-existent pixels for fill the new space that is created when the "landscape mode" is just started: Surface/View should adapts itself and it takes few milliseconds which are few frames as you reported (more the Device is slow/cheap and more frames are affected by this behavious/issue) expecially for the Camera to get new pixels from a different orientation.
Although Camera API is deprecated, it's simpler to get started than Camera2. But the document seems not to be that easy to understand(with my reading ability). I've searched a lot trying to figure it out. But there're still bunch of questions.
1.What is camera's orientation? Is there any definition that I miss? There're 4 dimensions(left, top, right, bottom) of camera. When we say orientation, which one is used and what is the relative object?
2.Why it's different between camera's orientation and device's?
3.Could you please tell me how to understand the algorithm given in the document of Camera.setDisplayOrientation() and Camera.parameters.setRotation()? There're sample code given by document for these two methods. These two algorithm both use sum and difference of orientation/rotation. I may use it directly in my project. But what does that mean exactly?
Besides, taking back-facing camera as example, the former uses (info.orientation - degrees + 360) % 360, while the latter uses (info.orientation + orientation) % 360. Confusing:/
Thanks if you can answer any of these questions above or just share some of your thoughts and experiences.
1. it is the how the camera is orientated in your device
2. Device orientation is the current orientation/rotation of your device (landscape/portrait )
3. Camera.setDisplayOrientation()
affects the preview
Camera.parameters.setRotation()
affects the result pictures (jpeg etc.)
Documentation:
Camera.setDisplayOrientation()
Set the clockwise rotation of preview display in degrees. This affects
the preview frames and the picture displayed after snapshot. This
method is useful for portrait mode applications. Note that preview
display of front-facing cameras is flipped horizontally before the
rotation, that is, the image is reflected along the central vertical
axis of the camera sensor. So the users can see themselves as looking
into a mirror.
Camera.parameters.setRotation()
Sets the clockwise rotation angle in degrees relative to the orientation of the camera. This affects the pictures returned from JPEG Camera.PictureCallback. The camera driver may set orientation in the EXIF header without rotating the picture. Or the driver may rotate the picture and the EXIF thumbnail. If the Jpeg picture is rotated, the orientation in the EXIF header will be missing or 1 (row #0 is top and column #0 is left side).
UPDATE : question is about Camera2
I'm trying to figure out who applies the rotation transform when a camera preview is drawn on a SurfaceTexture.
When requesting the preview sizes from the camera you always get pairs where the width is larger than the height (because landscape is the usual orientation when taking a picture).
When using the device on portrait mode and setting the preview size (for ex. 1600 x1200) the frames from the camera are correctly rotated but I can't find out where it's done, is it something CameraDevice does automatically based on Surface type ? or is it the SurfaceTexture who rotates the image?
The answer depends a bit on which camera API you're using; since you mention CameraDevice, I assume you mean camera2.
In camera2, one of the goals was to simplify the rotation handling where possible; so if you draw preview into a SurfaceView, the camera service and the hardware compositor / GPU cooperate and handle all the rotation for you. You always request landscape resolutions from the sensor (which is aligned with the long edge of the sensor matching the long edge of the device), and you just need to make sure your SurfaceView's aspect ratio matches that of the requested resolution (so in portrait, you need 9:16 View to display 1080p correctly; in landscape you need a 16:9 View).
For TextureView, and completely custom GL drawing with SurfaceTexture, the API can't do it all for you. The SurfaceTexture's transform is set by the camera API to rotate the camera output to the device's native orientation (generally portrait for phones, landscape for some tablets), but it can't handle the additional rotation if your app's UI is not in the native orientation.
In that case, you'll need to get the transform matrix from the SurfaceTexure, apply the extra rotation to match your app UI, and set that as the TextureView matrix.
It's been about a year since I worked on Camera stuff, so I apologize for a lack of specifics. But I do remember that the key when displaying the Camera preview was calculating the correct transform matrix to apply to the SurfaceView (or TextureView) to apply any scaling or rotation that is needed. So regarding "who is doing the rotation" I guess you can say it is the view, as instructed by the Transform that you supply. So the matrix will be based on the relationship of the preview resolution you request (from the list of what's capable for your device) compared to the actual laid out dimensions of your view, plus the physical orientation of the device sensor as compared to the current orientation of the device screen.
In the old camera API, Camera.CameraInfo has an orientation field that supplies the physical orientation with which the sensor is mounted. It's typically 90 for a landscape mounted sensor on most phones, but you'll also find some 270s out there (effectively "upside down"). 0 and 180 may exist but I've never seen them.
i just played thru the android camera tutorial. the problem i have is about orientation. the recorded videos have wrong orientation if i start in portrait mode.
In my case i modified the layout of preview view a bit - now it has some wrong/arbitrary aspect ration but the recorded videos do also have the same (wrong) aspect ratio!?
Why and how are preview and actual recording coupled? is there a way to decouple it: the recorded video should only record what the camera delivers.
So how to create a camera app that ignores orientation on recording (or uses orientation only to store it in metadata) but reflects it in preview (nothing to do - a portrait becomes landscape by rotating the phone). are there any examples of camera apps with correct rotation handling?
If you want to record video on Android with a different orientation from the default, you need to use MediaRecorder's setOrientationHint method.
There is no coupling of camera preview orientation (set by Camera's setDisplayOrientation method) and recording orientation, beyond that they both default to be oriented along the long side of the device.
If you change your app's orientation away from landscape, you need to call Camera's setDisplayOrientation to properly adjust preview, and Media Recorder's setOrientationHint to change the recording orientation, independently.
Android's default camera application, available in AOSP, properly handles all this.
mSession = SessionBuilder.getInstance()
.setContext(getApplicationContext())
.setAudioEncoder(SessionBuilder.AUDIO_AAC)
.setAudioQuality(new AudioQuality(8000, 16000))
.setVideoEncoder(SessionBuilder.VIDEO_H264)
.setSurfaceView(mSurfaceView).setPreviewOrientation(90)
.setCallback(this).build();
In my camera app, the UI orientation is fixed to portrait.
the preview displayed correctly on both landscape and portrait by setting camera.setdisplayorientation(90).
I can take picture and save it to file.
when I display it by ImageView,
the picture that was taken in landscape orientation could display correctly.
(the top of phone in my left side)
But... the one that was taken in portrait orientation is not so lucky...
It looks like turn 90 degrees to left.
I try to detect the device orientation through sensor so that I can set the EXIF header,
but... so far...that too hard to achieve for me...does any one can help me to solve this problem?
Use the getRotation method:
Display display = ((WindowManager)
context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int rotation = display.getRotation();
From the documentation:
Returns the rotation of the screen from its "natural" orientation.
The returned value may be Surface.ROTATION_0 (no rotation), Surface.ROTATION_90, Surface.
ROTATION_180, or Surface.ROTATION_270.
For example, if a device has a naturally tall screen, and the user has turned it on its side to go into a landscape orientation, the value returned here may be either Surface.ROTATION_90 or Surface.ROTATION_270 depending on the direction it was turned.
The angle is the rotation of the drawn graphics on the screen, which is the opposite direction of the physical rotation of the device.
For example, if the device is rotated 90 degrees counter-clockwise, to compensate rendering will be rotated by 90 degrees clockwise and thus the returned value here will be Surface.ROTATION_90.
getRotation was introduced from Android 2.2. Use getOrientation if your target are older devices.
Got answer form here:
how to detect orientation of android device?
If you just want to detect orientation of the device then you can use an OrientationEventListener.
here's the official docs:
http://developer.android.com/reference/android/view/OrientationEventListener.html#onOrientationChanged(int)
But before you use anything, check out this excellent blog post about orientation handling in android:
http://android-developers.blogspot.in/2010/09/one-screen-turn-deserves-another.html