|
|
@ -14,7 +14,7 @@
|
|
|
|
* limitations under the License.
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
package com.example.android.camera2raw;
|
|
|
|
package com.xypower.mppreview;
|
|
|
|
|
|
|
|
|
|
|
|
import android.Manifest;
|
|
|
|
import android.Manifest;
|
|
|
|
import android.app.Activity;
|
|
|
|
import android.app.Activity;
|
|
|
@ -66,6 +66,7 @@ import android.view.Surface;
|
|
|
|
import android.view.TextureView;
|
|
|
|
import android.view.TextureView;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
|
|
|
|
import android.widget.Switch;
|
|
|
|
import android.widget.Toast;
|
|
|
|
import android.widget.Toast;
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.File;
|
|
|
@ -301,13 +302,6 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private RefCountedAutoCloseable<ImageReader> mJpegImageReader;
|
|
|
|
private RefCountedAutoCloseable<ImageReader> mJpegImageReader;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* A reference counted holder wrapping the {@link ImageReader} that handles RAW image captures.
|
|
|
|
|
|
|
|
* This is used to allow us to clean up the {@link ImageReader} when all background tasks using
|
|
|
|
|
|
|
|
* its {@link Image}s have completed.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private RefCountedAutoCloseable<ImageReader> mRawImageReader;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Whether or not the currently configured camera device is fixed-focus.
|
|
|
|
* Whether or not the currently configured camera device is fixed-focus.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
@ -323,11 +317,6 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private final TreeMap<Integer, ImageSaver.ImageSaverBuilder> mJpegResultQueue = new TreeMap<>();
|
|
|
|
private final TreeMap<Integer, ImageSaver.ImageSaverBuilder> mJpegResultQueue = new TreeMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Request ID to {@link ImageSaver.ImageSaverBuilder} mapping for in-progress RAW captures.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private final TreeMap<Integer, ImageSaver.ImageSaverBuilder> mRawResultQueue = new TreeMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* {@link CaptureRequest.Builder} for the camera preview
|
|
|
|
* {@link CaptureRequest.Builder} for the camera preview
|
|
|
|
*/
|
|
|
|
*/
|
|
|
@ -411,20 +400,6 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a
|
|
|
|
|
|
|
|
* RAW image is ready to be saved.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private final ImageReader.OnImageAvailableListener mOnRawImageAvailableListener
|
|
|
|
|
|
|
|
= new ImageReader.OnImageAvailableListener() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void onImageAvailable(ImageReader reader) {
|
|
|
|
|
|
|
|
dequeueAndSaveImage(mRawResultQueue, mRawImageReader);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* A {@link CameraCaptureSession.CaptureCallback} that handles events for the preview and
|
|
|
|
* A {@link CameraCaptureSession.CaptureCallback} that handles events for the preview and
|
|
|
|
* pre-capture sequence.
|
|
|
|
* pre-capture sequence.
|
|
|
@ -513,9 +488,6 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
|
|
|
|
public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
|
|
|
|
long timestamp, long frameNumber) {
|
|
|
|
long timestamp, long frameNumber) {
|
|
|
|
String currentDateTime = generateTimestamp();
|
|
|
|
String currentDateTime = generateTimestamp();
|
|
|
|
File rawFile = new File(Environment.
|
|
|
|
|
|
|
|
getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
|
|
|
|
|
|
|
|
"RAW_" + currentDateTime + ".dng");
|
|
|
|
|
|
|
|
File jpegFile = new File(Environment.
|
|
|
|
File jpegFile = new File(Environment.
|
|
|
|
getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
|
|
|
|
getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
|
|
|
|
"JPEG_" + currentDateTime + ".jpg");
|
|
|
|
"JPEG_" + currentDateTime + ".jpg");
|
|
|
@ -523,15 +495,12 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
// Look up the ImageSaverBuilder for this request and update it with the file name
|
|
|
|
// Look up the ImageSaverBuilder for this request and update it with the file name
|
|
|
|
// based on the capture start time.
|
|
|
|
// based on the capture start time.
|
|
|
|
ImageSaver.ImageSaverBuilder jpegBuilder;
|
|
|
|
ImageSaver.ImageSaverBuilder jpegBuilder;
|
|
|
|
ImageSaver.ImageSaverBuilder rawBuilder;
|
|
|
|
|
|
|
|
int requestId = (int) request.getTag();
|
|
|
|
int requestId = (int) request.getTag();
|
|
|
|
synchronized (mCameraStateLock) {
|
|
|
|
synchronized (mCameraStateLock) {
|
|
|
|
jpegBuilder = mJpegResultQueue.get(requestId);
|
|
|
|
jpegBuilder = mJpegResultQueue.get(requestId);
|
|
|
|
rawBuilder = mRawResultQueue.get(requestId);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (jpegBuilder != null) jpegBuilder.setFile(jpegFile);
|
|
|
|
if (jpegBuilder != null) jpegBuilder.setFile(jpegFile);
|
|
|
|
if (rawBuilder != null) rawBuilder.setFile(rawFile);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
@ -545,23 +514,15 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
// Look up the ImageSaverBuilder for this request and update it with the CaptureResult
|
|
|
|
// Look up the ImageSaverBuilder for this request and update it with the CaptureResult
|
|
|
|
synchronized (mCameraStateLock) {
|
|
|
|
synchronized (mCameraStateLock) {
|
|
|
|
jpegBuilder = mJpegResultQueue.get(requestId);
|
|
|
|
jpegBuilder = mJpegResultQueue.get(requestId);
|
|
|
|
rawBuilder = mRawResultQueue.get(requestId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (jpegBuilder != null) {
|
|
|
|
if (jpegBuilder != null) {
|
|
|
|
jpegBuilder.setResult(result);
|
|
|
|
jpegBuilder.setResult(result);
|
|
|
|
sb.append("Saving JPEG as: ");
|
|
|
|
sb.append("Saving JPEG as: ");
|
|
|
|
sb.append(jpegBuilder.getSaveLocation());
|
|
|
|
sb.append(jpegBuilder.getSaveLocation());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rawBuilder != null) {
|
|
|
|
|
|
|
|
rawBuilder.setResult(result);
|
|
|
|
|
|
|
|
if (jpegBuilder != null) sb.append(", ");
|
|
|
|
|
|
|
|
sb.append("Saving RAW as: ");
|
|
|
|
|
|
|
|
sb.append(rawBuilder.getSaveLocation());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If we have all the results necessary, save the image to a file in the background.
|
|
|
|
// If we have all the results necessary, save the image to a file in the background.
|
|
|
|
handleCompletionLocked(requestId, jpegBuilder, mJpegResultQueue);
|
|
|
|
handleCompletionLocked(requestId, jpegBuilder, mJpegResultQueue);
|
|
|
|
handleCompletionLocked(requestId, rawBuilder, mRawResultQueue);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
finishedCaptureLocked();
|
|
|
|
finishedCaptureLocked();
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -575,7 +536,6 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
int requestId = (int) request.getTag();
|
|
|
|
int requestId = (int) request.getTag();
|
|
|
|
synchronized (mCameraStateLock) {
|
|
|
|
synchronized (mCameraStateLock) {
|
|
|
|
mJpegResultQueue.remove(requestId);
|
|
|
|
mJpegResultQueue.remove(requestId);
|
|
|
|
mRawResultQueue.remove(requestId);
|
|
|
|
|
|
|
|
finishedCaptureLocked();
|
|
|
|
finishedCaptureLocked();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
showToast("Capture failed!");
|
|
|
|
showToast("Capture failed!");
|
|
|
@ -612,6 +572,17 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
// view.findViewById(R.id.info).setOnClickListener(this);
|
|
|
|
// view.findViewById(R.id.info).setOnClickListener(this);
|
|
|
|
mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
|
|
|
|
mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
view.findViewById(R.id.hdr).setOnClickListener(new View.OnClickListener() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void onClick(View v) {
|
|
|
|
|
|
|
|
closeCamera();
|
|
|
|
|
|
|
|
// stopBackgroundThread();
|
|
|
|
|
|
|
|
// startBackgroundThread();
|
|
|
|
|
|
|
|
openCamera();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Setup a new OrientationEventListener. This is used to handle rotation events like a
|
|
|
|
// Setup a new OrientationEventListener. This is used to handle rotation events like a
|
|
|
|
// 180 degree rotation that do not normally trigger a call to onCreate to do view re-layout
|
|
|
|
// 180 degree rotation that do not normally trigger a call to onCreate to do view re-layout
|
|
|
|
// or otherwise cause the preview TextureView's size to change.
|
|
|
|
// or otherwise cause the preview TextureView's size to change.
|
|
|
@ -701,19 +672,23 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
show(getFragmentManager(), "dialog");
|
|
|
|
show(getFragmentManager(), "dialog");
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
View rootView = getView();
|
|
|
|
|
|
|
|
Switch hdrSwitch = (Switch)(rootView.findViewById(R.id.hdr));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean hdrChecked = hdrSwitch.isChecked();
|
|
|
|
|
|
|
|
final String expectedCameraId = hdrChecked ? "1" : "0";
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// Find a CameraDevice that supports RAW captures, and configure state.
|
|
|
|
// Find a CameraDevice that supports RAW captures, and configure state.
|
|
|
|
for (String cameraId : manager.getCameraIdList()) {
|
|
|
|
for (String cameraId : manager.getCameraIdList()) {
|
|
|
|
CameraCharacteristics characteristics
|
|
|
|
|
|
|
|
= manager.getCameraCharacteristics(cameraId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We only use a camera that supports RAW in this sample.
|
|
|
|
if (!TextUtils.equals(cameraId, expectedCameraId)) {
|
|
|
|
if (!contains(characteristics.get(
|
|
|
|
|
|
|
|
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES),
|
|
|
|
|
|
|
|
CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CameraCharacteristics characteristics
|
|
|
|
|
|
|
|
= manager.getCameraCharacteristics(cameraId);
|
|
|
|
|
|
|
|
|
|
|
|
StreamConfigurationMap map = characteristics.get(
|
|
|
|
StreamConfigurationMap map = characteristics.get(
|
|
|
|
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
|
|
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
|
|
|
|
|
|
|
|
|
@ -722,10 +697,6 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
|
|
|
|
Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
|
|
|
|
new CompareSizesByArea());
|
|
|
|
new CompareSizesByArea());
|
|
|
|
|
|
|
|
|
|
|
|
Size largestRaw = Collections.max(
|
|
|
|
|
|
|
|
Arrays.asList(map.getOutputSizes(ImageFormat.RAW_SENSOR)),
|
|
|
|
|
|
|
|
new CompareSizesByArea());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
synchronized (mCameraStateLock) {
|
|
|
|
synchronized (mCameraStateLock) {
|
|
|
|
// Set up ImageReaders for JPEG and RAW outputs. Place these in a reference
|
|
|
|
// Set up ImageReaders for JPEG and RAW outputs. Place these in a reference
|
|
|
|
// counted wrapper to ensure they are only closed when all background tasks
|
|
|
|
// counted wrapper to ensure they are only closed when all background tasks
|
|
|
@ -738,14 +709,6 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
mJpegImageReader.get().setOnImageAvailableListener(
|
|
|
|
mJpegImageReader.get().setOnImageAvailableListener(
|
|
|
|
mOnJpegImageAvailableListener, mBackgroundHandler);
|
|
|
|
mOnJpegImageAvailableListener, mBackgroundHandler);
|
|
|
|
|
|
|
|
|
|
|
|
if (mRawImageReader == null || mRawImageReader.getAndRetain() == null) {
|
|
|
|
|
|
|
|
mRawImageReader = new RefCountedAutoCloseable<>(
|
|
|
|
|
|
|
|
ImageReader.newInstance(largestRaw.getWidth(),
|
|
|
|
|
|
|
|
largestRaw.getHeight(), ImageFormat.RAW_SENSOR, /*maxImages*/ 5));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
mRawImageReader.get().setOnImageAvailableListener(
|
|
|
|
|
|
|
|
mOnRawImageAvailableListener, mBackgroundHandler);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mCharacteristics = characteristics;
|
|
|
|
mCharacteristics = characteristics;
|
|
|
|
mCameraId = cameraId;
|
|
|
|
mCameraId = cameraId;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -875,10 +838,6 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
mJpegImageReader.close();
|
|
|
|
mJpegImageReader.close();
|
|
|
|
mJpegImageReader = null;
|
|
|
|
mJpegImageReader = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (null != mRawImageReader) {
|
|
|
|
|
|
|
|
mRawImageReader.close();
|
|
|
|
|
|
|
|
mRawImageReader = null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
|
|
|
|
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
|
|
|
@ -935,8 +894,7 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
|
|
|
|
|
|
|
|
// Here, we create a CameraCaptureSession for camera preview.
|
|
|
|
// Here, we create a CameraCaptureSession for camera preview.
|
|
|
|
mCameraDevice.createCaptureSession(Arrays.asList(surface,
|
|
|
|
mCameraDevice.createCaptureSession(Arrays.asList(surface,
|
|
|
|
mJpegImageReader.get().getSurface(),
|
|
|
|
mJpegImageReader.get().getSurface()), new CameraCaptureSession.StateCallback() {
|
|
|
|
mRawImageReader.get().getSurface()), new CameraCaptureSession.StateCallback() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
|
|
|
|
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
|
|
|
|
synchronized (mCameraStateLock) {
|
|
|
|
synchronized (mCameraStateLock) {
|
|
|
@ -1047,8 +1005,11 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
|
|
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
|
|
|
|
|
|
|
|
|
|
// For still image captures, we always use the largest available size.
|
|
|
|
// For still image captures, we always use the largest available size.
|
|
|
|
Size largestJpeg = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
|
|
|
|
Size[] resolutions = map.getHighResolutionOutputSizes(ImageFormat.JPEG);
|
|
|
|
new CompareSizesByArea());
|
|
|
|
if (resolutions == null) {
|
|
|
|
|
|
|
|
resolutions = map.getOutputSizes(ImageFormat.JPEG);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Size largestJpeg = Collections.max(Arrays.asList(resolutions), new CompareSizesByArea());
|
|
|
|
|
|
|
|
|
|
|
|
// Find the rotation of the device relative to the native device orientation.
|
|
|
|
// Find the rotation of the device relative to the native device orientation.
|
|
|
|
int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
|
|
|
|
int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
|
|
|
@ -1215,7 +1176,6 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
|
|
|
|
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
|
|
|
|
|
|
|
|
|
|
|
|
captureBuilder.addTarget(mJpegImageReader.get().getSurface());
|
|
|
|
captureBuilder.addTarget(mJpegImageReader.get().getSurface());
|
|
|
|
captureBuilder.addTarget(mRawImageReader.get().getSurface());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Use the same AE and AF modes as the preview.
|
|
|
|
// Use the same AE and AF modes as the preview.
|
|
|
|
setup3AControlsLocked(captureBuilder);
|
|
|
|
setup3AControlsLocked(captureBuilder);
|
|
|
@ -1238,7 +1198,6 @@ public class Camera2RawFragment extends Fragment
|
|
|
|
.setCharacteristics(mCharacteristics);
|
|
|
|
.setCharacteristics(mCharacteristics);
|
|
|
|
|
|
|
|
|
|
|
|
mJpegResultQueue.put((int) request.getTag(), jpegBuilder);
|
|
|
|
mJpegResultQueue.put((int) request.getTag(), jpegBuilder);
|
|
|
|
mRawResultQueue.put((int) request.getTag(), rawBuilder);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mCaptureSession.capture(request, mCaptureCallback, mBackgroundHandler);
|
|
|
|
mCaptureSession.capture(request, mCaptureCallback, mBackgroundHandler);
|
|
|
|
|
|
|
|
|