I used code from here. But there is one problem, I can´t change camera orientation. Final video is upside down.
I tried to change it by this (I tried all possible values - 0,90,180,270):
camera.setDisplayOrientation(90);
camera.getParameters().setRotation(90);
or
camera.getParameters().set("orientation", "portrait");
camera.getParameters().set("rotation", 90);
But nothing works. Any idea how to setup it?
I tested it on Nexus 5X with Android 7.1.1.
I want to use fixed orientation, no matter how I hold device, orientation must remain same.
camera.setDisplayOrientation(90) This affects the preview frames and the picture displayed after snapshot. This does not affect the order of byte array passed in onPreviewFrame, JPEG pictures, or recorded videos. So you can't change the REC orientation using this API. If you want to change the REC orientation, you should rotate the every frame date in onPreviewFrame or rotate the SurfaceTexture base on the way you record video.
use mediaRecorder.setOrientationHint(180);
Related
The problem appears on my Nexus 6P device. After going through all the motions to detect optimal previews, aspect ratios, video sizes etc, I end up with the following:
SurfaceView dimens 2392x1440 (full screen)
Once re-measured with the aspect ratio of the camera preview resolution, this changes to 2560x1440 or 2392x1351 depending on the calculation method.
Camera preview size: 1920x1080
This is set on the camera params using setPreviewSize():
params.setPreviewSize(mOptimalPreviewSizes.width, mOptimalPreviewSizes.height);
Media recorder video size: 1920x1080 (forced by the settings)
This is set on the media recorder:
mMediaRecorder.setVideoSize(mOptimalVideoSize.width, mOptimalVideoSize.height);
When I click the record button, the camera preview 'zooms in', i.e. resizes to video size. If I change the video size setting to for example 3840x2160, the preview works fine with no resizing.
I was under impression that it is possible to set video size separatly to the preview size, so I'm a bit confused to why I'm seeing this and how can I work around this.
EDIT:
As an example, OpenCamera seems to be able to separate preview surface resolution from video resolution. https://sourceforge.net/p/opencamera/code/ci/master/tree/src/net/sourceforge/opencamera/
To make sure, I've added a line just before video_recorder.prepare(); to set a custom video size (video_recorder.setVideoSize(640,480);). The preview surface was still measuring near full screen at 2392x1351, and camera preview was still set to 1920x1080. I've also double checked the resulting video and it was 640x480 as expected. Unfortunately I cannot see anything in their code that would indicate how this is achieved.
EDIT 2:
I've also noticed that this 'zooming' action always happens to a specific resolution/value. Regardless of whether I'm recording at 1920x1080 or 320x200, the preview gets zoomed and looses about a cm of the picture that was available before the recording started. The end video has the expected cropping in relation to the resolution.
The problem seems to be related to the video stabilisation. I suppose this actually makes sense as stabilising against shakes usually requires cropping and when the preview resolution is already significantly lower than the surface size, it causes the picture to 'jump' or 'zoom' in. Removing video stabilisation fixes the issue.
I looked everywhere for a solution but couldn't use anything useful. I'm using SurfaceView and FrameLayout for custom in-app camera. I have a button that calls "mCamera.takePicture()" function. In the Callback, I save the picture as it is; the problem is that the picture is rotated and flipped, and scaled in weird ratio.
I know that it is happening mostly because I set the camera parameter's setPreviewSize to an optimal size, and rotated it using mCamera.setDisplayOrientation(). The preview looks beautiful. But when I take a picture and save it, that's where it gets messed up.
Camera.Parameters cp = mCamera.getParameters();
Size theSize = getOptimalPreviewSize(opt, w, h);
cp.setPreviewSize(theSize.width, theSize.height);
mCamera.setDisplayOrientation(90);
mCamera.setParameters(cp);
The above code is written in surfaceChanged function.
How do I make the saved picture as it's shown in the preview?
Screenshot of what is shown in the preview of the camera. Size fine, rotation fine:
This is after the picture has been taken. Look at the monitor, collection of CDs and the plug. It's squashed and the monitor looks like a wave:
The image returned in pictureTaken() is not effected by Camera.setDisplayOrientation(). It is in Jpeg compressed format, so you can set JPEG rotation via Exif header without decoding it. This is what Camera.setRotation() often does, but on some devices it actually performs rotation in hardware. This is the most efficient method, but some viewers may still show a rotated image.
Alternatively, you can use JPEG lossless rotation, using jpegtran.
On SourceForge, there is a Java open source class LLJTran. The Android port is on GitHub.
I want to record Video using front facing camera. Using the example from here as reference. I changed the getCamerainstance method to getFrontFacingCamera. I am able to see the preview while recording. But when i close the recording and play the video, it is always some horizontal flickering lines. Seems like some encoding issue. I tried- changing the media recorder profile to QUALITY_LOW/ QUALITY_HIGH, - Setting the frame rate to 15. the same app works perfectly when i use rear camera.
P.S: I have set the preview's(surface view's) size to 208×208. (Should this affect? , It's working fine with rear camera).
Thanks
Finally solved it. (In case someone faces the same issue)
need to use: mediaRecorder.setVideoSize(320,240);
I am attempting to allow users to record video that is a different size than the actual on-screen preview that they can see while recording. This seems to be possible from this documentation concerning the getSupportedVideoSizes function which states:
If the returned list is not null, the returned list will contain at
least one Size and one of the sizes in the returned list must be
passed to MediaRecorder.setVideoSize() for camcorder application if
camera is used as the video source. In this case, the size of the
preview can be different from the resolution of the recorded video
during video recording.
This suggests that some phones will return null from this fn (in my experience the Galaxy SIII does) but for those who do not, it is possible to provide a preview with a different resolution than the actual video. Is this understanding correct? Do some phones allow the behavior and others not?
Attempting a Solution:
In the official description of the setPreviewDisplay function, which is used in the lengthy process of setting up for video recording, it is mentioned that:
If this method is called with null surface or not called at all, media
recorder will not change the preview surface of the camera.
This seems to be what I want, but unfortunately if I do this, the whole video recording process is completely messed up. I am assuming that this function can not be passed null or not called at all in the process of recording video. Perhaps in other contexts this is okay. Unfortunately though, this does not seem to help me.
My only next steps are to look into TextureViews and to use a preview Texture as opposed to a typical SurfaceView implementation in order to use openGL to stretch the texture to my desired size that differs from the actual resolution (and crop any excess off the screen), and then to Construct a Surface for the setPreviewDisplay function with the Surface(SurfaceTexture surfaceTexture) constructor for a Surface. I would like to avoid using a TextureView due to incompatibility below ICS, and also because this adds significant complexity.
This seems like a delicate process, but I am hoping someone can offer some advice in this area.
Thank you.
a.Assume the user sets the size of x,y as video size
b.Now with getSupportedVideoSizes function get the entire list and see if x,y falls in one of them and set the MediaRecorder.setVideoSize().If x,y does not fall in the getSupportedVideoSizes list,then set the default profile for the video record.
This is about the video size
Now coming to the preview size,Not much workaround options.
Take a RelativeLayout which holds the SurfaceView.
<android.view.SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
preview is the name of the SurfaceView.
Here i have given a sample of re-sizing it to half of the width and height.
resetCamera(); //reset the camera
ViewGroup.LayoutParams params = preview.getLayoutParams();
RelativeLayout myRelLayout = (RelativeLayout) findViewById(R.id.myRelLayout);
params.width = (int) (myRelLayout.getWidth()/2);
params.height = (int)(myRelLayout.getHeight()/2);
preview.setLayoutParams(params);
initCamera(); //initiate the camera(open camera, set parameter, setPreviewDisplay,startPreview)
please look at the resolution of the preview and then scale down the height or width accordingly based on the video size.
Hope it helps.
As you mention, this is only possible when getSupportedVideoSizes() returns a non-null list.
But if you do see a non-null list, then this simple approach should work:
Set the desired preview resolution with setPreviewSize; the size you select has to be one of the sizes given from getSupportedPreviewSizes.
Set the preview display to your SurfaceView or SurfaceTexture with setPreviewDisplay or setPreviewTexture, respectively.
Start preview.
Create the media recorder, and set its video size either directly with setVideoSize using one of the sizes from getSupportedVideoSizes, or use one of the predefined Camcorder profiles to configure all the media recorder settings for a given quality/size.
Pass the camera object to MediaRecorder's setCamera call, configure the rest of the media recorder, and start recording.
On devices with a non-null getSupportedVideoSizes list, this should result in preview staying at the resolution set by your setPreviewSize call, with recording operating at the set video size/camcorder profile resolution. On devices with no supported video sizes, the preview size will be reset by the MediaRecorder to match the recording size. You should be able to test this by setting a very low preview resolution and a high recording resolution (say, 160x120 for preview, 720p for recording). It should be obvious if the MediaRecorder switches the preview resolution to 720p when recording starts, as the preview quality will jump substantially.
Note that the preview size is not directly linked to the dimensions of the display SurfaceView; the output of the camera preview will be scaled to fit into the SurfaceView, so if your SurfaceView's dimensions are, say 100x100 pixels due to your layout and device, whatever the preview resolution you use will be scaled to 100x100 for display. So you still need to make sure to keep the SurfaceView's aspect ratio correct so that the preview is not distorted.
And for power efficiency, you should not use a preview resolution much higher than the actual number of pixels in your SurfaceView, since the additional resolution will be lost in fitting the preview in the surfaceview. This is of course only possible for recording when getSupportedVideoSizes() returns a non-null value.
First, I will try to answer your specific questions.
it is possible to provide a preview with a different resolution than the actual video. Is this understanding correct?
Yes, preview size is more often than not different from recording size. Preview size is more often than not linked to your display size. So if a phone has display of CIF (352 x 288), but is capable of recording D1 (720 x 480), then preview size and recording size will be different. I feel that other experts have answered sufficiently on this point.
Do some phones allow the behavior and others not?
Most of the latest phones support this feature except maybe a few low-end ones.
Along with setPreviewDisplay, we have to consider this point also:
The one exception is that if the preview surface is not set (or set to null) before startPreview() is called, then this method may be called once with a non-null parameter to set the preview surface. (This allows camera setup and surface creation to happen in parallel, saving time.) The preview surface may not otherwise change while preview is running.
Could you please share the issue faced by you when setPreviewDisplay is invoked with a NULL surface?
I'm writing a small android app where a user can place an image inside the live preview of the camera and take a picture of this. The app will then combine the two images appropriately -- All of this is working fine.
I understand you can get/set the PreviewSize using Camera.getParameters(), I assume this is related to the size of the realtime "camera feed".
However, the size of my SurfaceView where the camera preview is shown is different from the reported (and used) PreviewSizes. For example, in the emulator my available SurfaceView happens to be 360x215, while the PreviewSize is 320x240. Still, the entire SurfaceView is filled with the preview.
But the picture that's generated in the end is (also?) 320x240. How does android compensate for these differences in size and aspect ratio? Is the image truncated?
Or am I simply misunderstanding what the PreviewSize is about - is this related to the size of the generated pictures, or is it related to the "realtime preview" that's projected on the SurfaceView? Are there any non-trivial Camera examples that deal with this?
I need to know how what transformation takes place to, eventually, copy/scale the image correctly into the photo, hence these questions.
I am trying to figure this out myself. Here is what I found out so far..
The surface view has an internal surface called mSurface which is actually used as camera feed and the encoder feed. So this buffer has to be the actual size at which you want do the recording.
You can set the size of this mSurface to be independent of the SurfaceView by using the setFixedSize method
Now you might want to perform a HD recording so the mSurface needs to 1280x760 resolution but you SurfaceView can't be that big (Assuming you are running it on a phone with a WVGA screen). So you try to set to a smaller resolution than 1280x760 which also maintains the same aspect ratio.
Android now performs a resizing on the HD buffer to get the preview resolution, cropping is not done, it is just resized to the SurfaceView reoslutions
So at this point both the mSurface and the previewSize that you set to the camera is the same resolution and hence the resultant video recording will also be of the same resolution.
That being said I am still struggling to get my VGA recorder to work on Nexus S, it is working on a LG Maha device. :)