|
|
|
@ -3,12 +3,15 @@ package com.otaliastudios.cameraview.picture; |
|
|
|
|
import android.hardware.camera2.CameraAccessException; |
|
|
|
|
import android.hardware.camera2.CameraDevice; |
|
|
|
|
import android.hardware.camera2.CaptureRequest; |
|
|
|
|
import android.hardware.camera2.DngCreator; |
|
|
|
|
import android.hardware.camera2.TotalCaptureResult; |
|
|
|
|
import android.media.Image; |
|
|
|
|
import android.media.ImageReader; |
|
|
|
|
import android.os.Build; |
|
|
|
|
|
|
|
|
|
import com.otaliastudios.cameraview.CameraLogger; |
|
|
|
|
import com.otaliastudios.cameraview.PictureResult; |
|
|
|
|
import com.otaliastudios.cameraview.controls.PictureFormat; |
|
|
|
|
import com.otaliastudios.cameraview.engine.Camera2Engine; |
|
|
|
|
import com.otaliastudios.cameraview.engine.action.Action; |
|
|
|
|
import com.otaliastudios.cameraview.engine.action.ActionHolder; |
|
|
|
@ -16,8 +19,11 @@ import com.otaliastudios.cameraview.engine.action.BaseAction; |
|
|
|
|
import com.otaliastudios.cameraview.internal.utils.ExifHelper; |
|
|
|
|
import com.otaliastudios.cameraview.internal.utils.WorkerHandler; |
|
|
|
|
|
|
|
|
|
import java.io.BufferedOutputStream; |
|
|
|
|
import java.io.ByteArrayInputStream; |
|
|
|
|
import java.io.ByteArrayOutputStream; |
|
|
|
|
import java.io.IOException; |
|
|
|
|
import java.io.OutputStream; |
|
|
|
|
import java.nio.ByteBuffer; |
|
|
|
|
|
|
|
|
|
import androidx.annotation.NonNull; |
|
|
|
@ -39,6 +45,8 @@ public class Full2PictureRecorder extends PictureRecorder |
|
|
|
|
private final ImageReader mPictureReader; |
|
|
|
|
private final CaptureRequest.Builder mPictureBuilder; |
|
|
|
|
|
|
|
|
|
private DngCreator mDngCreator; |
|
|
|
|
|
|
|
|
|
public Full2PictureRecorder(@NonNull PictureResult.Stub stub, |
|
|
|
|
@NonNull Camera2Engine engine, |
|
|
|
|
@NonNull CaptureRequest.Builder pictureBuilder, |
|
|
|
@ -54,7 +62,9 @@ public class Full2PictureRecorder extends PictureRecorder |
|
|
|
|
protected void onStart(@NonNull ActionHolder holder) { |
|
|
|
|
super.onStart(holder); |
|
|
|
|
mPictureBuilder.addTarget(mPictureReader.getSurface()); |
|
|
|
|
mPictureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mResult.rotation); |
|
|
|
|
if (mResult.format == PictureFormat.JPEG) { |
|
|
|
|
mPictureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mResult.rotation); |
|
|
|
|
} |
|
|
|
|
mPictureBuilder.setTag(CameraDevice.TEMPLATE_STILL_CAPTURE); |
|
|
|
|
try { |
|
|
|
|
holder.applyBuilder(this, mPictureBuilder); |
|
|
|
@ -75,6 +85,20 @@ public class Full2PictureRecorder extends PictureRecorder |
|
|
|
|
setState(STATE_COMPLETED); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public void onCaptureCompleted(@NonNull ActionHolder holder, |
|
|
|
|
@NonNull CaptureRequest request, |
|
|
|
|
@NonNull TotalCaptureResult result) { |
|
|
|
|
super.onCaptureCompleted(holder, request, result); |
|
|
|
|
if (mResult.format == PictureFormat.DNG) { |
|
|
|
|
mDngCreator = new DngCreator(holder.getCharacteristics(this), result); |
|
|
|
|
mDngCreator.setOrientation(mResult.rotation); |
|
|
|
|
if (mResult.location != null) { |
|
|
|
|
mDngCreator.setLocation(mResult.location); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -86,24 +110,37 @@ public class Full2PictureRecorder extends PictureRecorder |
|
|
|
|
@Override |
|
|
|
|
public void onImageAvailable(ImageReader reader) { |
|
|
|
|
LOG.i("onImageAvailable started."); |
|
|
|
|
// Read the JPEG.
|
|
|
|
|
Image image = null; |
|
|
|
|
//noinspection TryFinallyCanBeTryWithResources
|
|
|
|
|
try { |
|
|
|
|
image = reader.acquireNextImage(); |
|
|
|
|
ByteBuffer buffer = image.getPlanes()[0].getBuffer(); |
|
|
|
|
byte[] bytes = new byte[buffer.remaining()]; |
|
|
|
|
buffer.get(bytes); |
|
|
|
|
mResult.data = bytes; |
|
|
|
|
switch (mResult.format) { |
|
|
|
|
case JPEG: readJpegImage(image); break; |
|
|
|
|
case DNG: readRawImage(image); break; |
|
|
|
|
default: throw new IllegalStateException("Unknown format: " + mResult.format); |
|
|
|
|
} |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
mResult = null; |
|
|
|
|
mError = e; |
|
|
|
|
dispatchResult(); |
|
|
|
|
return; |
|
|
|
|
} finally { |
|
|
|
|
if (image != null) image.close(); |
|
|
|
|
if (image != null) { |
|
|
|
|
image.close(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Leave.
|
|
|
|
|
LOG.i("onImageAvailable ended."); |
|
|
|
|
dispatchResult(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void readJpegImage(@NonNull Image image) { |
|
|
|
|
ByteBuffer buffer = image.getPlanes()[0].getBuffer(); |
|
|
|
|
byte[] bytes = new byte[buffer.remaining()]; |
|
|
|
|
buffer.get(bytes); |
|
|
|
|
mResult.data = bytes; |
|
|
|
|
|
|
|
|
|
// Just like Camera1, unfortunately, the camera might rotate the image
|
|
|
|
|
// and put EXIF=0 instead of respecting our EXIF and leave the image unaltered.
|
|
|
|
|
mResult.rotation = 0; |
|
|
|
@ -113,9 +150,19 @@ public class Full2PictureRecorder extends PictureRecorder |
|
|
|
|
ExifInterface.ORIENTATION_NORMAL); |
|
|
|
|
mResult.rotation = ExifHelper.readExifOrientation(exifOrientation); |
|
|
|
|
} catch (IOException ignore) { } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Leave.
|
|
|
|
|
LOG.i("onImageAvailable ended."); |
|
|
|
|
dispatchResult(); |
|
|
|
|
private void readRawImage(@NonNull Image image) { |
|
|
|
|
ByteArrayOutputStream array = new ByteArrayOutputStream(); |
|
|
|
|
BufferedOutputStream stream = new BufferedOutputStream(array); |
|
|
|
|
try { |
|
|
|
|
mDngCreator.writeImage(stream, image); |
|
|
|
|
stream.flush(); |
|
|
|
|
mResult.data = array.toByteArray(); |
|
|
|
|
} catch (IOException e) { |
|
|
|
|
mDngCreator.close(); |
|
|
|
|
try { stream.close(); } catch (IOException ignore) {} |
|
|
|
|
throw new RuntimeException(e); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|