Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix focus and camera handling for newer iOS devices with triple cameras (+ other fixes) #342

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
50d492f
chore(*): update podfile
michaelwolz Jun 6, 2024
9ec31de
fix(ios): use native camera selection for optimal focus
michaelwolz Jun 6, 2024
9d7f6ac
fix(camera-controller): prefer regular wide angle camera over dual wi…
michaelwolz Jun 11, 2024
9e1a744
feat: camera up and running
michaelwolz Jun 21, 2024
30764a5
refactor(ios): large refactoring
michaelwolz Jun 22, 2024
f0fea9a
fix(ios): auto focus / zoom level
michaelwolz Jun 22, 2024
52f3a6c
chore: clean up and documentation
michaelwolz Jun 24, 2024
5595256
fix: re-enable high resolution output for iOS
michaelwolz Jun 24, 2024
631bb38
chore: documentation
michaelwolz Jun 24, 2024
2a664f4
fix(ios): improve performance when opening camera
michaelwolz Jun 24, 2024
5a858d4
fix: add permissions methods
michaelwolz Jun 24, 2024
e941601
fix: do not use virtual device on older iphones
michaelwolz Jun 24, 2024
5f34b76
fix(web): add missing implementations for web platform
michaelwolz Jun 24, 2024
f2d96d6
fix(ios): set photo preset for high resolution mode
michaelwolz Jun 25, 2024
9bd7af3
fix(ios): check focus / exposure mode support
michaelwolz Jun 26, 2024
5480293
fix(ios): initialize photo output before applying zoom factor
michaelwolz Jun 30, 2024
a3fe1fc
fix(ios): repair switching camera behavior
michaelwolz Jul 3, 2024
db16c0f
fix(android): front camera rotation
michaelwolz Jul 3, 2024
6dbccb6
fix(android): image rotation logic for front camera
michaelwolz Jul 3, 2024
bc57883
fix(ios): camera initialization on ios
michaelwolz Jul 4, 2024
93b5b74
docs: remove iOS support for video recording
michaelwolz Jul 8, 2024
0a846ed
feat(*): remove video recording functions
michaelwolz Jul 12, 2024
8fba530
docs: update readme
michaelwolz Jul 12, 2024
ea00fb1
docs: update readme
michaelwolz Aug 9, 2024
5f8a96b
fix(ios): improve type safety to prevent crashes
michaelwolz Aug 13, 2024
a158c61
Merge branch 'master' into release/next
michaelwolz Aug 13, 2024
dc2f4a8
Merge pull request #1 from michaelwolz/release/next
michaelwolz Aug 16, 2024
9b05b89
fix: update dependencies
michaelwolz Aug 16, 2024
a461347
chore: modify license
michaelwolz Aug 16, 2024
7dbfa49
build: add missing file references for iOS
michaelwolz Aug 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
MIT License

Copyright (c) Ariel Hernandez Musa.
Copyright (c) Ariel Hernandez Musa
Copyright (c) 2024 Michael Wolz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
274 changes: 29 additions & 245 deletions README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,25 @@

import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.media.AudioManager;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
Expand All @@ -53,14 +43,8 @@ public interface CameraPreviewListener {
void onPictureTakenError(String message);
void onSnapshotTaken(String originalPicture);
void onSnapshotTakenError(String message);
void onFocusSet(int pointX, int pointY);
void onFocusSetError(String message);
void onBackButton();
void onCameraStarted();
void onStartRecordVideo();
void onStartRecordVideoError(String message);
void onStopRecordVideo(String file);
void onStopRecordVideoError(String error);
}

private CameraPreviewListener eventListener;
Expand All @@ -84,9 +68,6 @@ private enum RecordingState {
STOPPED
}

private RecordingState mRecordingState = RecordingState.INITIALIZING;
private MediaRecorder mRecorder = null;
private String recordFilePath;
private float opacity;

// The first rear facing camera
Expand Down Expand Up @@ -765,35 +746,19 @@ public void run() {
params.setJpegQuality(quality);
}

if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT && disableExifHeaderStripping) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraCurrentlyLocked, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT && disableExifHeaderStripping) {
Activity activity = getActivity();
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 180;
break;
case Surface.ROTATION_180:
degrees = 270;
break;
case Surface.ROTATION_270:
degrees = 0;
break;
}
int orientation;
Camera.CameraInfo info = new Camera.CameraInfo();
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
orientation = (info.orientation + degrees) % 360;
if (degrees != 0) {
orientation = (360 - orientation) % 360;
}
} else {
orientation = (info.orientation - degrees + 360) % 360;
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
params.setRotation(orientation);
params.setRotation((info.orientation + degrees) % 360);
} else {
params.setRotation(mPreview.getDisplayOrientation());
}
Expand All @@ -808,140 +773,6 @@ public void run() {
}
}

public void startRecord(
final String filePath,
final String camera,
final int width,
final int height,
final int quality,
final boolean withFlash,
final int maxDuration
) {
Log.d(TAG, "CameraPreview startRecord camera: " + camera + " width: " + width + ", height: " + height + ", quality: " + quality);
Activity activity = getActivity();
muteStream(true, activity);
if (this.mRecordingState == RecordingState.STARTED) {
Log.d(TAG, "Already Recording");
return;
}

this.recordFilePath = filePath;
int mOrientationHint = calculateOrientationHint();
int videoWidth = 0; //set whatever
int videoHeight = 0; //set whatever

Camera.Parameters cameraParams = mCamera.getParameters();
if (withFlash) {
cameraParams.setFlashMode(withFlash ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF);
mCamera.setParameters(cameraParams);
mCamera.startPreview();
}

mCamera.unlock();
mRecorder = new MediaRecorder();

try {
mRecorder.setCamera(mCamera);

CamcorderProfile profile;
if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_HIGH)) {
profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_HIGH);
} else {
if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_480P)) {
profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_480P);
} else {
if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_720P)) {
profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_720P);
} else {
if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_1080P)) {
profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_1080P);
} else {
profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_LOW);
}
}
}
}

mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION);
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mRecorder.setProfile(profile);
mRecorder.setOutputFile(filePath);
mRecorder.setOrientationHint(mOrientationHint);
mRecorder.setMaxDuration(maxDuration);

mRecorder.prepare();
Log.d(TAG, "Starting recording");
mRecorder.start();
eventListener.onStartRecordVideo();
} catch (IOException e) {
eventListener.onStartRecordVideoError(e.getMessage());
}
}

public int calculateOrientationHint() {
DisplayMetrics dm = new DisplayMetrics();
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(defaultCameraId, info);
int cameraRotationOffset = info.orientation;
Activity activity = getActivity();

activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
int currentScreenRotation = activity.getWindowManager().getDefaultDisplay().getRotation();

int degrees = 0;
switch (currentScreenRotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}

int orientation;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
orientation = (cameraRotationOffset + degrees) % 360;
if (degrees != 0) {
orientation = (360 - orientation) % 360;
}
} else {
orientation = (cameraRotationOffset - degrees + 360) % 360;
}
Log.w(TAG, "************orientationHint ***********= " + orientation);

return orientation;
}

public void stopRecord() {
Log.d(TAG, "stopRecord");

try {
mRecorder.stop();
mRecorder.reset(); // clear recorder configuration
mRecorder.release(); // release the recorder object
mRecorder = null;
mCamera.lock();
Camera.Parameters cameraParams = mCamera.getParameters();
cameraParams.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mCamera.setParameters(cameraParams);
mCamera.startPreview();
eventListener.onStopRecordVideo(this.recordFilePath);
} catch (Exception e) {
eventListener.onStopRecordVideoError(e.getMessage());
}
}

public void muteStream(boolean mute, Activity activity) {
AudioManager audioManager = ((AudioManager) activity.getApplicationContext().getSystemService(Context.AUDIO_SERVICE));
int direction = mute ? audioManager.ADJUST_MUTE : audioManager.ADJUST_UNMUTE;
}

public void setFocusArea(final int pointX, final int pointY, final Camera.AutoFocusCallback callback) {
if (mCamera != null) {
mCamera.cancelAutoFocus();
Expand Down
Loading