How to fix the orientation of previewDisplay in surfaceView? - android

This is how it is showing
Here's the code and I tried a lot of things related to aspect ratio and preview size. The video is getting saved correctly as I want to be in portrait mode.
enter code here
camera?.let {
val params = it.parameters
params.set("orientation","portrait")
params.setRotation(90)
val surfaceView = binding.surfaceView
val previewSizes = camera?.parameters?.supportedPreviewSizes
val surfaceHolder = surfaceView.holder
camera?.setPreviewDisplay(surfaceHolder)
camera?.startPreview()
}
// Initialize media recorder
mediaRecorder = MediaRecorder()
mediaRecorder?.let {
it.setAudioSource(MediaRecorder.AudioSource.MIC)
it.setVideoSource(MediaRecorder.VideoSource.CAMERA)
it.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
it.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
it.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
it.setVideoFrameRate(30)
it.setVideoEncodingBitRate(10000000)
it.setOrientationHint(90) // Set the orientation of the video to portrait mode
it.setPreviewDisplay(surfaceView.holder.surface)
it.setOutputFile(getOutputFile().path)
}

Related

ImageProxy return wrong getRotationDegrees

I have normal portrait orientation in the emulator and int rotation has zero value. Everything is fine.
void bindPreview(#NonNull ProcessCameraProvider cameraProvider) {
int rotation = cameraView.getDisplay().getRotation(); // 0
// Preview
Preview preview = new Preview.Builder()
.setTargetAspectRatio(AspectRatio.RATIO_4_3)
.build();
// Camera
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
// Create image capture
imageCapture = new ImageCapture.Builder()
.setTargetResolution(new Size(1200, 720))
.setTargetRotation(rotation)
.build();
// ViewPort
Rational aspectRatio = new Rational(cameraView.getWidth(), cameraView.getHeight());
ViewPort viewPort = new ViewPort.Builder(aspectRatio, rotation).build();
// Use case
UseCaseGroup useCaseGroup = new UseCaseGroup.Builder()
.addUseCase(preview)
.addUseCase(imageCapture)
.setViewPort(viewPort)
.build();
}
But after in imageCapture.takePicture callback
public void onCaptureSuccess(#NonNull ImageProxy image) {
imageRotationDegrees = image.getImageInfo().getRotationDegrees(); // 90
}
imageRotationDegrees return 90! means that the image must be rotated to get the natural orientation, but it is not! Its value should be 0.
Is it normal?
update:
On device I get 0 on imageRotationDegrees.
On emulator I got 90 on imageRotationDegrees
But all images come in the correct orientation regardless of this value. How do I know which image I should rotate if I have to?
Yes, it is normal for the imageRotationDegrees value to be different from the value of rotation in the bindPreview method.
The rotation value represents the rotation of the device's screen, while the imageRotationDegrees value represents the orientation of the image as captured by the camera. These values can be different because the camera and the screen are not necessarily oriented in the same way.
For example, if the device is in portrait orientation with the camera facing the user, the rotation value will be 0, but the imageRotationDegrees value will be 90 because the camera is capturing the image rotated 90 degrees from the device's portrait orientation.
To get the natural orientation of the image, you can rotate the image by the value of imageRotationDegrees. For example, if you are using the Android's Bitmap class to represent the image, you can use the rotate method to rotate the image by the correct amount:
Bitmap rotatedImage = Bitmap.createBitmap(image, 0, 0, image.getWidth(), image.getHeight(), matrix, true);
Okey. If is not right please write me:
Hardware devices has a varios sensor rotation.
"imageRotationDegrees=0" on emulator means screen_height = sensor_height
"imageRotationDegrees=90" on device means screen_height = sensor_width
Depending on the rotation I get different values from "image.getCropRect()".
I check the imageRotationDegrees and calculate the correct frame for cropping
if (imageRotationDegrees == 0 || imageRotationDegrees == 180) {
} else {
}
Additional info:
getRotationDegrees is different on imageCapture and imageAnalysis on device

cameraX android capturing more area while image capture

I am trying camexaX library for capturing the image but it is capturing more space from left and right.
I captured the area between Q to O alphabet in preview but it has captured more area around Q and O.
/**
* Bind the Camera to the lifecycle
*/
private fun bindCamera(){
CameraX.unbindAll()
// Preview config for the camera
val previewConfig = PreviewConfig.Builder()
.setLensFacing(lensFacing)
.build()
val preview = Preview(previewConfig)
// Image capture config which controls the Flash and Lens
val imageCaptureConfig = ImageCaptureConfig.Builder()
.setTargetRotation(windowManager.defaultDisplay.rotation)
.setLensFacing(lensFacing)
.setFlashMode(FlashMode.ON)
.build()
imageCapture = ImageCapture(imageCaptureConfig)
// The view that displays the preview
val textureView: TextureView = findViewById(R.id.view_finder)
// Handles the output data of the camera
preview.setOnPreviewOutputUpdateListener { previewOutput ->
// Displays the camera image in our preview view
textureView.surfaceTexture = previewOutput.surfaceTexture
}
// Bind the camera to the lifecycle
CameraX.bindToLifecycle(this as LifecycleOwner, imageCapture, preview)
}
Can some one help me here?
This is normal behaviour because your camera records wider angle than your Preview can show. Preview will only adapt the picture height and width to the size that it can display and ImageCapture will capture the picture independently as if there is no Preview.
It is important to realize that all of the use cases CameraX provide (Preview, ImageAnalysis and ImageCapture) can work independently. Meaning, you can use your ImageCapture even without the Preview. Same goes for the ImageAnalysis and Preveiw.

MediaProjection for screen capture - How to change resolution?

Take this block of example code:
// from window manager
val recordWidth = screenWidth
val recordHeight = screenHeight
val projection: MediaProjection = // retrieved from API
val mediaRecorder = MediaRecorder().apply {
setVideoSource(SURFACE)
setOutputFormat(MPEG_4)
setVideoFrameRate(frameRate) // e.g. 30
setVideoEncoder(H264)
setVideoSize(recordWidth, recordHeight)
setVideoEncodingBitRate(videoBitRate)
setOutputFile(outputFile)
prepare()
}
val virtualDisplay: VirtualDisplay = projection?.createVirtualDisplay(
"Example",
screenWidth,
screenHeight,
screenDensity,
VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mediaRecorder.surface,
null,
null
)
mediaRecorder.start()
This all works well, as long as screenWidth and screenHeight match that of the display.
If I change recordWidth and recordHeight (which are passed to the MediaRecorder with setVideoSize(Int, Int)), then all goes wrong. The recorded video tends to contain just the upper left section of the overall screen.
So my main questions:
Does something special have to be done to reduce resolution when
recording the screen? Even if I keep the aspect ratio with the
screen, it doesn't seem to work.
Some width/height values cause a
crash - is there an API to retrieve supported screen recording
sizes? I know Camera provides one, but this isn't really using the
Camera APIs.
I think you can refer this one
this.mMediaProjection = mMediaProjectionManager.getMediaProjection(resultCode, resultData);
Log.d(TAG, "startRecording...");
this.mVideoBufferInfo = new MediaCodec.BufferInfo();
MediaFormat mediaFormat = MediaFormat.createVideoFormat(format, width, height);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, FPS);
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 0);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);

Auto-exposure doesn't work Android Camera API v1

I'm trying to use camera features as part of my application and I'm stuck on camera preview step.
I want to understand why the preview image remains dark if there are no bright light.
Here is what params I set before start previewing:
mParameters = mCamera.getParameters();
List<Camera.Size> mSupportedPreviewSizes = mParameters.getSupportedPreviewSizes();
Camera.Size optimalSize = CameraHelper.getOptimalPreviewSize(mSupportedPreviewSizes, DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT);
// Use the same size for recording profile.
mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
mProfile.videoFrameWidth = optimalSize.width;
mProfile.videoFrameHeight = optimalSize.height;
// likewise for the camera object itself.
mParameters.setPreviewSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
// Set correct video width and height according to screen rotation
transformMatrixHelper.setVideoDimensions(optimalSize.width, optimalSize.height);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
transformMatrixHelper.setVideoDimensions(optimalSize.height, optimalSize.width);
}
transformMatrixHelper.clearInitTextureDimension();
mParameters.setPreviewFpsRange(MAX_FPS, MAX_FPS);
mParameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
// Auto-focus
if (mParameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
// Auto-exposure
if (mParameters.isAutoExposureLockSupported()) {
mParameters.setAutoExposureLock(false);
}
mCamera.setParameters(mParameters);
I'm not calling any camera.autoFocus(callback) method after preview stared.
I will be very grateful if someone help me, thanks.

Android Camera Preview on a square screen stretched

I'm building an app for Android but The device do have a square screen. The screen is 320x320 and the camera app use the SurfaceView to show the preview as below :
mCameraView = (SurfaceView) findViewById(R.id.surface);
LayoutParams params = mCameraView.getLayoutParams();
int camera_dimension = getResources().getInteger(R.integer.camera_dimension);
params.height = camera_dimension; //320px
params.width = camera_dimension;
mCameraView.setLayoutParams(params);
mCameraViewHolder = mCameraView.getHolder();
mCameraViewHolder.addCallback(this);
mCameraViewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
On Surface changed, I'm doing this and it works but the supporter preview is w480 x h320
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
int mWidth = w;
int mHeight = h;
int mFormat = format;
try {
mCameraAccess.mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
Camera.Parameters param = mCameraAccess.mCamera.getParameters();
List<Camera.Size> SupportedPreview = param.getSupportedPreviewSizes();
int ScreenSize = getResources().getInteger(R.integer.camera_dimension);
for (int i = 0; i < SupportedPreview.size(); i++) {
if (SupportedPreview.get(i).height == ScreenSize) {
param.setPreviewSize(SupportedPreview.get(i).width, SupportedPreview.get(i).height);
break;
}
}
mCameraAccess.mCamera.setParameters(param);
mCameraAccess.mCamera.startPreview();
}
How can make sure that my preview inside the viewholder is not compressed but a kind of centercrop. As the preview is a rectangle, I just need the square centered on the image. Usually I'm using scaleType but it's not supported in Surface view
Any idea ?
The solution which i have figured out is:
1)-Keep surface view full screen,so that is doesn't stretch.
2)-Put a view over surfaceview with full opacity.So that is looks like camera is already squared.
3)-After capturing image or video,you will have to crop them.
For video you have to use some video processing library like javacv.Using this library you can extract video frames,convert them to bitmap,crop bitmap in square and then re-encode into video.
To get accurate results you will need to play around with different techniques like zooming camera during capture etc. according to your needs.
Original Image:
Squared Image:

Categories

Resources