|
|
@ -38,9 +38,9 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
private Runnable mPostFocusResetRunnable = new Runnable() { |
|
|
|
private Runnable mPostFocusResetRunnable = new Runnable() { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void run() { |
|
|
|
public void run() { |
|
|
|
|
|
|
|
synchronized (mLock) { |
|
|
|
if (!isCameraAvailable()) return; |
|
|
|
if (!isCameraAvailable()) return; |
|
|
|
mCamera.cancelAutoFocus(); |
|
|
|
mCamera.cancelAutoFocus(); |
|
|
|
synchronized (mLock) { |
|
|
|
|
|
|
|
Camera.Parameters params = mCamera.getParameters(); |
|
|
|
Camera.Parameters params = mCamera.getParameters(); |
|
|
|
params.setFocusAreas(null); |
|
|
|
params.setFocusAreas(null); |
|
|
|
params.setMeteringAreas(null); |
|
|
|
params.setMeteringAreas(null); |
|
|
@ -54,7 +54,6 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
private boolean mIsSetup = false; |
|
|
|
private boolean mIsSetup = false; |
|
|
|
private boolean mIsCapturingImage = false; |
|
|
|
private boolean mIsCapturingImage = false; |
|
|
|
private boolean mIsCapturingVideo = false; |
|
|
|
private boolean mIsCapturingVideo = false; |
|
|
|
private final Object mLock = new Object(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Camera1(CameraView.CameraCallbacks callback) { |
|
|
|
Camera1(CameraView.CameraCallbacks callback) { |
|
|
@ -90,7 +89,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void onSurfaceChanged() { |
|
|
|
public void onSurfaceChanged() { |
|
|
|
LOG.i("onSurfaceChanged, size is", mPreview.getSurfaceSize()); |
|
|
|
LOG.i("onSurfaceChanged, size is", mPreview.getSurfaceSize()); |
|
|
|
if (mIsSetup) { |
|
|
|
if (mIsSetup && isCameraAvailable()) { |
|
|
|
// Compute a new camera preview size.
|
|
|
|
// Compute a new camera preview size.
|
|
|
|
Size newSize = computePreviewSize(); |
|
|
|
Size newSize = computePreviewSize(); |
|
|
|
if (!newSize.equals(mPreviewSize)) { |
|
|
|
if (!newSize.equals(mPreviewSize)) { |
|
|
@ -440,11 +439,11 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean capturePicture() { |
|
|
|
void capturePicture() { |
|
|
|
if (mIsCapturingImage) return false; |
|
|
|
if (mIsCapturingImage) return; |
|
|
|
if (!isCameraAvailable()) return false; |
|
|
|
if (!isCameraAvailable()) return; |
|
|
|
if (mSessionType == SessionType.VIDEO && mIsCapturingVideo) { |
|
|
|
if (mSessionType == SessionType.VIDEO && mIsCapturingVideo) { |
|
|
|
if (!mOptions.isVideoSnapshotSupported()) return false; |
|
|
|
if (!mOptions.isVideoSnapshotSupported()) return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Set boolean to wait for image callback
|
|
|
|
// Set boolean to wait for image callback
|
|
|
@ -461,7 +460,15 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
// We must consider exifOrientation to bring back the picture in the sensor world.
|
|
|
|
// We must consider exifOrientation to bring back the picture in the sensor world.
|
|
|
|
// Then use sensorToDisplay to move to the display world, where CameraView lives.
|
|
|
|
// Then use sensorToDisplay to move to the display world, where CameraView lives.
|
|
|
|
final boolean consistentWithView = (exifRotation + sensorToDisplay + 180) % 180 == 0; |
|
|
|
final boolean consistentWithView = (exifRotation + sensorToDisplay + 180) % 180 == 0; |
|
|
|
mCamera.takePicture(null, null, null, |
|
|
|
mCamera.takePicture( |
|
|
|
|
|
|
|
new Camera.ShutterCallback() { |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public void onShutter() { |
|
|
|
|
|
|
|
mCameraCallbacks.onShutter(false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
null, |
|
|
|
|
|
|
|
null, |
|
|
|
new Camera.PictureCallback() { |
|
|
|
new Camera.PictureCallback() { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void onPictureTaken(byte[] data, final Camera camera) { |
|
|
|
public void onPictureTaken(byte[] data, final Camera camera) { |
|
|
@ -476,24 +483,25 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
mCameraCallbacks.processImage(data, consistentWithView, exifFlip); |
|
|
|
mCameraCallbacks.processImage(data, consistentWithView, exifFlip); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean captureSnapshot() { |
|
|
|
void captureSnapshot() { |
|
|
|
if (!isCameraAvailable()) return false; |
|
|
|
if (!isCameraAvailable()) return; |
|
|
|
if (mIsCapturingImage) return false; |
|
|
|
if (mIsCapturingImage) return; |
|
|
|
// This won't work while capturing a video.
|
|
|
|
// This won't work while capturing a video.
|
|
|
|
// Switch to capturePicture.
|
|
|
|
// Switch to capturePicture.
|
|
|
|
if (mIsCapturingVideo) { |
|
|
|
if (mIsCapturingVideo) { |
|
|
|
capturePicture(); |
|
|
|
capturePicture(); |
|
|
|
return false; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
mIsCapturingImage = true; |
|
|
|
mIsCapturingImage = true; |
|
|
|
mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() { |
|
|
|
mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void onPreviewFrame(final byte[] data, Camera camera) { |
|
|
|
public void onPreviewFrame(final byte[] data, Camera camera) { |
|
|
|
|
|
|
|
mCameraCallbacks.onShutter(true); |
|
|
|
|
|
|
|
|
|
|
|
// Got to rotate the preview frame, since byte[] data here does not include
|
|
|
|
// Got to rotate the preview frame, since byte[] data here does not include
|
|
|
|
// EXIF tags automatically set by camera. So either we add EXIF, or we rotate.
|
|
|
|
// EXIF tags automatically set by camera. So either we add EXIF, or we rotate.
|
|
|
|
// Adding EXIF to a byte array, unfortunately, is hard.
|
|
|
|
// Adding EXIF to a byte array, unfortunately, is hard.
|
|
|
@ -520,11 +528,10 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
|
|
|
|
|
|
|
|
// It seems that the buffers are already cleared here, so we need to allocate again.
|
|
|
|
// It seems that the buffers are already cleared here, so we need to allocate again.
|
|
|
|
mCamera.setPreviewCallbackWithBuffer(null); // Release anything left
|
|
|
|
mCamera.setPreviewCallbackWithBuffer(null); // Release anything left
|
|
|
|
mCamera.setPreviewCallbackWithBuffer(this); // Add ourselves
|
|
|
|
mCamera.setPreviewCallbackWithBuffer(Camera1.this); // Add ourselves
|
|
|
|
mFrameManager.allocate(ImageFormat.getBitsPerPixel(mPreviewFormat), mPreviewSize); mCamera.setPreviewCallbackWithBuffer(Camera1.this); |
|
|
|
mFrameManager.allocate(ImageFormat.getBitsPerPixel(mPreviewFormat), mPreviewSize); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
@ -643,9 +650,9 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean startVideo(@NonNull File videoFile) { |
|
|
|
void startVideo(@NonNull File videoFile) { |
|
|
|
if (mIsCapturingVideo) return false; |
|
|
|
if (mIsCapturingVideo) return; |
|
|
|
if (!isCameraAvailable()) return false; |
|
|
|
if (!isCameraAvailable()) return; |
|
|
|
if (mSessionType == SessionType.VIDEO) { |
|
|
|
if (mSessionType == SessionType.VIDEO) { |
|
|
|
mVideoFile = videoFile; |
|
|
|
mVideoFile = videoFile; |
|
|
|
mIsCapturingVideo = true; |
|
|
|
mIsCapturingVideo = true; |
|
|
@ -653,13 +660,11 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
try { |
|
|
|
try { |
|
|
|
mMediaRecorder.prepare(); |
|
|
|
mMediaRecorder.prepare(); |
|
|
|
mMediaRecorder.start(); |
|
|
|
mMediaRecorder.start(); |
|
|
|
return true; |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
} catch (Exception e) { |
|
|
|
LOG.e("Error while starting MediaRecorder. Swallowing.", e); |
|
|
|
LOG.e("Error while starting MediaRecorder. Swallowing.", e); |
|
|
|
mVideoFile = null; |
|
|
|
mVideoFile = null; |
|
|
|
mCamera.lock(); |
|
|
|
mCamera.lock(); |
|
|
|
endVideo(); |
|
|
|
endVideo(); |
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
throw new IllegalStateException("Can't record video while session type is picture"); |
|
|
|
throw new IllegalStateException("Can't record video while session type is picture"); |
|
|
@ -667,7 +672,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean endVideo() { |
|
|
|
void endVideo() { |
|
|
|
if (mIsCapturingVideo) { |
|
|
|
if (mIsCapturingVideo) { |
|
|
|
mIsCapturingVideo = false; |
|
|
|
mIsCapturingVideo = false; |
|
|
|
if (mMediaRecorder != null) { |
|
|
|
if (mMediaRecorder != null) { |
|
|
@ -685,9 +690,7 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
mCameraCallbacks.dispatchOnVideoTaken(mVideoFile); |
|
|
|
mCameraCallbacks.dispatchOnVideoTaken(mVideoFile); |
|
|
|
mVideoFile = null; |
|
|
|
mVideoFile = null; |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -771,33 +774,42 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean setZoom(float zoom) { |
|
|
|
void setZoom(float zoom, PointF[] points, boolean notify) { |
|
|
|
if (!isCameraAvailable()) return false; |
|
|
|
if (!isCameraAvailable()) return; |
|
|
|
if (!mOptions.isZoomSupported()) return false; |
|
|
|
if (!mOptions.isZoomSupported()) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mZoomValue = zoom; |
|
|
|
synchronized (mLock) { |
|
|
|
synchronized (mLock) { |
|
|
|
Camera.Parameters params = mCamera.getParameters(); |
|
|
|
Camera.Parameters params = mCamera.getParameters(); |
|
|
|
float max = params.getMaxZoom(); |
|
|
|
float max = params.getMaxZoom(); |
|
|
|
params.setZoom((int) (zoom * max)); |
|
|
|
params.setZoom((int) (zoom * max)); |
|
|
|
mCamera.setParameters(params); |
|
|
|
mCamera.setParameters(params); |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (notify) { |
|
|
|
|
|
|
|
mCameraCallbacks.dispatchOnZoomChanged(zoom, points); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean setExposureCorrection(float EVvalue) { |
|
|
|
void setExposureCorrection(float EVvalue, float[] bounds, PointF[] points, boolean notify) { |
|
|
|
if (!isCameraAvailable()) return false; |
|
|
|
if (!isCameraAvailable()) return; |
|
|
|
if (!mOptions.isExposureCorrectionSupported()) return false; |
|
|
|
if (!mOptions.isExposureCorrectionSupported()) return; |
|
|
|
|
|
|
|
|
|
|
|
float max = mOptions.getExposureCorrectionMaxValue(); |
|
|
|
float max = mOptions.getExposureCorrectionMaxValue(); |
|
|
|
float min = mOptions.getExposureCorrectionMinValue(); |
|
|
|
float min = mOptions.getExposureCorrectionMinValue(); |
|
|
|
EVvalue = EVvalue < min ? min : EVvalue > max ? max : EVvalue; // cap
|
|
|
|
EVvalue = EVvalue < min ? min : EVvalue > max ? max : EVvalue; // cap
|
|
|
|
|
|
|
|
mExposureCorrectionValue = EVvalue; |
|
|
|
synchronized (mLock) { |
|
|
|
synchronized (mLock) { |
|
|
|
Camera.Parameters params = mCamera.getParameters(); |
|
|
|
Camera.Parameters params = mCamera.getParameters(); |
|
|
|
int indexValue = (int) (EVvalue / params.getExposureCompensationStep()); |
|
|
|
int indexValue = (int) (EVvalue / params.getExposureCompensationStep()); |
|
|
|
params.setExposureCompensation(indexValue); |
|
|
|
params.setExposureCompensation(indexValue); |
|
|
|
mCamera.setParameters(params); |
|
|
|
mCamera.setParameters(params); |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
|
|
if (notify) { |
|
|
|
|
|
|
|
mCameraCallbacks.dispatchOnExposureCorrectionChanged(EVvalue, bounds, points); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// -----------------
|
|
|
|
// -----------------
|
|
|
@ -805,9 +817,9 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean startAutoFocus(@Nullable final Gesture gesture, PointF point) { |
|
|
|
void startAutoFocus(@Nullable final Gesture gesture, PointF point) { |
|
|
|
if (!isCameraAvailable()) return false; |
|
|
|
if (!isCameraAvailable()) return; |
|
|
|
if (!mOptions.isAutoFocusSupported()) return false; |
|
|
|
if (!mOptions.isAutoFocusSupported()) return; |
|
|
|
final PointF p = new PointF(point.x, point.y); // copy.
|
|
|
|
final PointF p = new PointF(point.x, point.y); // copy.
|
|
|
|
List<Camera.Area> meteringAreas2 = computeMeteringAreas(p.x, p.y); |
|
|
|
List<Camera.Area> meteringAreas2 = computeMeteringAreas(p.x, p.y); |
|
|
|
List<Camera.Area> meteringAreas1 = meteringAreas2.subList(0, 1); |
|
|
|
List<Camera.Area> meteringAreas1 = meteringAreas2.subList(0, 1); |
|
|
@ -832,7 +844,6 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -924,23 +935,15 @@ class Camera1 extends CameraController implements Camera.PreviewCallback { |
|
|
|
LOG.i("size:", "matchSize:", "found consistent:", consistent.size()); |
|
|
|
LOG.i("size:", "matchSize:", "found consistent:", consistent.size()); |
|
|
|
LOG.i("size:", "matchSize:", "found big enough and consistent:", bigEnoughAndConsistent.size()); |
|
|
|
LOG.i("size:", "matchSize:", "found big enough and consistent:", bigEnoughAndConsistent.size()); |
|
|
|
Size result; |
|
|
|
Size result; |
|
|
|
if (biggestPossible) { |
|
|
|
|
|
|
|
if (bigEnoughAndConsistent.size() > 0) { |
|
|
|
if (bigEnoughAndConsistent.size() > 0) { |
|
|
|
result = Collections.max(bigEnoughAndConsistent); |
|
|
|
result = biggestPossible ? |
|
|
|
|
|
|
|
Collections.max(bigEnoughAndConsistent) : |
|
|
|
|
|
|
|
Collections.min(bigEnoughAndConsistent); |
|
|
|
} else if (consistent.size() > 0) { |
|
|
|
} else if (consistent.size() > 0) { |
|
|
|
result = Collections.max(consistent); |
|
|
|
result = Collections.max(consistent); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
result = Collections.max(sizes); |
|
|
|
result = Collections.max(sizes); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
|
|
|
|
if (bigEnoughAndConsistent.size() > 0) { |
|
|
|
|
|
|
|
result = Collections.min(bigEnoughAndConsistent); |
|
|
|
|
|
|
|
} else if (consistent.size() > 0) { |
|
|
|
|
|
|
|
result = Collections.max(consistent); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
result = Collections.max(sizes); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
LOG.i("size", "matchSize:", "returning result", result); |
|
|
|
LOG.i("size", "matchSize:", "returning result", result); |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|