package cs495.pocketdslr; import android.app.Activity; import android.content.Context; import android.content.res.Resources; import android.graphics.ImageFormat; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.graphics.drawable.GradientDrawable; import android.hardware.camera2.*; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.Image; import android.media.ImageReader; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.util.Log; import android.util.Range; import android.util.Size; import android.view.Gravity; import android.view.Surface; import android.view.TextureView; import android.widget.Toast; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Random; /** * Created by Chris on 3/11/2015. */ public class PocketDSLRCamera implements CameraStateCallback, CameraCaptureSessionStateCallback, //TextureView.SurfaceTextureListener, CameraSettingChange, CameraCaptureSessionCallback, ImageReader.OnImageAvailableListener{ protected Context context; protected Activity activity; protected CameraManager cameraManager; protected CameraDevice cameraDevice; protected CameraCharacteristics cameraCharacteristics; protected String cameraId; protected Size cameraSize; protected Size rawCameraSize; protected long minOutputFrameDuration; protected TextureView cameraPreview; protected CaptureRequest.Builder cameraCaptureRequestBuilder; protected CameraCaptureSession cameraCaptureSession; protected UserContext userContext; protected Handler cameraPreviewHandler; protected Surface previewSurface; public PocketDSLRCamera(Activity activity, UserContext userContext, TextureView cameraPreview) { this.activity = activity; this.context = this.activity.getBaseContext(); this.userContext = userContext; this.cameraManager = (CameraManager)this.context.getSystemService(Context.CAMERA_SERVICE); this.cameraPreview = cameraPreview; } @Override public void onConfigureFailed(CameraCaptureSession session) { Toast.makeText(this.context, "Camera capture session failed", Toast.LENGTH_SHORT); } @Override public void onConfigured(CameraCaptureSession session) { this.cameraCaptureSession = session; if (this.cameraDevice == null) { return; } try { SurfaceTexture surfaceTexture = this.cameraPreview.getSurfaceTexture(); surfaceTexture.setDefaultBufferSize(this.cameraSize.getWidth(), this.cameraSize.getHeight()); this.previewSurface = new Surface(surfaceTexture); this.cameraCaptureRequestBuilder = this.cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); this.cameraCaptureRequestBuilder.addTarget(this.previewSurface); this.updateSettings(this.cameraCaptureRequestBuilder); HandlerThread cameraPreviewThread = new HandlerThread("cameraPreview"); cameraPreviewThread.start(); this.cameraPreviewHandler = new Handler(cameraPreviewThread.getLooper()); CaptureRequest captureRequest = this.cameraCaptureRequestBuilder.build(); this.cameraCaptureSession.setRepeatingRequest(captureRequest, null, this.cameraPreviewHandler); } catch(CameraAccessException e) { Log.w("pocketDSLR", e.getMessage(), e); } } //Setup preview @Override public void onCameraOpened(CameraDevice cameraDevice) { this.cameraDevice = cameraDevice; setupCameraPreview(); } @Override public void onCameraClosed(CameraDevice camera) { this.onCameraFinish(camera); } @Override public void onCameraDisconnected(CameraDevice camera) { this.onCameraFinish(camera); } @Override public void onCameraError(CameraDevice camera, int error) { this.onCameraFinish(camera); } public void close() { if (this.cameraDevice != null) { this.cameraDevice.close(); this.cameraDevice = null; } } public CameraCharacteristics getCameraCharacteristics() { return this.cameraCharacteristics; } public void onReadyState() { this.openCamera(); } protected void setupCameraPreview() { if (this.cameraPreview == null || this.cameraSize == null || this.cameraDevice == null){ return; } try { SurfaceTexture surfaceTexture = this.cameraPreview.getSurfaceTexture(); surfaceTexture.setDefaultBufferSize(this.cameraSize.getWidth(), this.cameraSize.getHeight()); Surface previewSurface = new Surface(surfaceTexture); List<Surface> previewSurfaces = new LinkedList<>(); previewSurfaces.add(previewSurface); CameraCaptureSessionStateCallbackBridge cameraCaptureSessionCallbackBridge = new CameraCaptureSessionStateCallbackBridge(this); this.cameraDevice.createCaptureSession(previewSurfaces, cameraCaptureSessionCallbackBridge, null); } catch (CameraAccessException e) { Log.println(0, "pocketDSLR", e.getMessage()); } } protected void openCamera() { try { this.cameraId = this.cameraManager.getCameraIdList()[0]; this.cameraCharacteristics = this.cameraManager.getCameraCharacteristics(this.cameraId); StreamConfigurationMap config = this.cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); this.cameraSize = config.getOutputSizes(SurfaceTexture.class)[0]; this.rawCameraSize = config.getOutputSizes(ImageFormat.RAW_SENSOR)[0]; this.minOutputFrameDuration = config.getOutputMinFrameDuration(ImageFormat.RAW_SENSOR, this.rawCameraSize); //this.applyTransform(this.cameraSize.getWidth(), this.cameraSize.getHeight()); CameraStateCallbackBridge cameraStateCallbackBridge = new CameraStateCallbackBridge(this); this.cameraManager.openCamera(this.cameraId, cameraStateCallbackBridge, null); } catch (CameraAccessException ex) { Log.println(0, "pocketDSLR", ex.getMessage()); Toast.makeText(this.context, "Unable to acquire camera", Toast.LENGTH_SHORT).show(); } } protected void onCameraFinish(CameraDevice cameraDevice){ if (this.cameraDevice == cameraDevice) { this.cameraDevice = null; } } protected void updateSettings(CaptureRequest.Builder builder) { //builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF); builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_MODE_OFF); builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_MODE_OFF); Integer isoSetting = this.userContext.getCameraSettings().getISO(); if (isoSetting != null) { builder.set(CaptureRequest.SENSOR_SENSITIVITY, isoSetting); } Long exposureSetting = this.userContext.getCameraSettings().getExposureTime(); if (exposureSetting != null) { builder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposureSetting); } Float apertureSetting = this.userContext.getCameraSettings().getAperture(); if (apertureSetting != null) { builder.set(CaptureRequest.LENS_FOCUS_DISTANCE, apertureSetting); } builder.set(CaptureRequest.SENSOR_FRAME_DURATION, this.minOutputFrameDuration); } private void applyTransform() { if (this.cameraPreview == null || this.cameraSize == null) { return; } RectF viewRect = new RectF(0, 0, this.cameraPreview.getWidth(), this.cameraPreview.getHeight()); RectF bufferRect = new RectF(0, 0, this.cameraSize.getWidth(), this.cameraSize.getHeight()); bufferRect.offset(viewRect.centerX() - bufferRect.centerX(), viewRect.centerY() - bufferRect.centerY()); Matrix transformMatrix = new Matrix(); transformMatrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.CENTER); int surfaceOrientation = this.activity.getWindowManager().getDefaultDisplay().getRotation(); transformMatrix.postRotate(surfaceOrientation * 90, viewRect.centerX(), viewRect.centerY()); this.cameraPreview.setTransform(transformMatrix); } public void takePicture() throws CameraAccessException { final ImageReader imageReader = ImageReader.newInstance(this.rawCameraSize.getWidth(), this.rawCameraSize.getHeight(), ImageFormat.RAW_SENSOR, 1); List<Surface> renderSurfaces = new LinkedList<Surface>(); renderSurfaces.add(imageReader.getSurface()); renderSurfaces.add(this.previewSurface); final CaptureRequest.Builder captureRequestBuilder = this.cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureRequestBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE, CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON); Range<Integer> availableFpsRanges[] = this.cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); Range<Integer> targetFps = availableFpsRanges[availableFpsRanges.length - 1]; captureRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetFps); captureRequestBuilder.addTarget(imageReader.getSurface()); int surfaceOrientation = this.activity.getWindowManager().getDefaultDisplay().getRotation(); switch (surfaceOrientation) { case Surface.ROTATION_0: surfaceOrientation = 90; break; case Surface.ROTATION_90: surfaceOrientation = 0; break; case Surface.ROTATION_180: surfaceOrientation = 270; break; case Surface.ROTATION_270: surfaceOrientation = 180; break; } captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, surfaceOrientation); this.updateSettings(captureRequestBuilder); HandlerThread handlerThread = new HandlerThread("TakePicture"); handlerThread.start(); final Handler threadHandler = new Handler(handlerThread.getLooper()); imageReader.setOnImageAvailableListener(this, threadHandler); //CameraCaptureSessionStateCallbackBridge cameraCaptureSessionStateCallbackBridge = new CameraCaptureSessionStateCallbackBridge(this); this.cameraDevice.createCaptureSession(renderSurfaces, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { try { session.capture(captureRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); resultRaw = result; } }, threadHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession session) { } }, threadHandler); } TotalCaptureResult resultRaw; @Override public void onImageAvailable(ImageReader reader) { DngSaver dngSaver = new DngSaver(userContext, reader, cameraCharacteristics, resultRaw); Thread thread = new Thread(dngSaver); thread.start(); // File appDirectory = new File(Environment.getExternalStorageDirectory() + "/pocketDSLR/"); // // if (!appDirectory.exists()){ // appDirectory.mkdirs(); // } // // SimpleDateFormat simpleDateFormatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss_"); // // Date currentDate = new Date(); // // Random randomGenerator = new Random(); // // final String imageFileName = appDirectory.toString() + simpleDateFormatter.format(currentDate) + randomGenerator.nextInt(1000) + ".dng"; // // File imageFile = new File(imageFileName); // // FileOutputStream imageFileStream = null; // try { // imageFileStream = new FileOutputStream(imageFile); // imageFileStream.write((byte)1); // } catch (FileNotFoundException e) { // e.printStackTrace(); // } catch (IOException e) { // e.printStackTrace(); // } // // DngCreator dngImageCreator = new DngCreator(cameraCharacteristics, resultRaw); // // try { // dngImageCreator.writeImage(imageFileStream, reader.acquireNextImage()); // } catch (IOException e) { // e.printStackTrace(); // } // // try { // imageFileStream.flush(); // imageFileStream.close(); // } catch (IOException e) { // e.printStackTrace(); // } // dngImageCreator.close(); this.setupCameraPreview(); } @Override public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { } @Override public void onSettingchange() { if (this.cameraCaptureSession == null){ return; } try { this.updateSettings(this.cameraCaptureRequestBuilder); this.cameraCaptureSession.setRepeatingRequest(this.cameraCaptureRequestBuilder.build(), null, this.cameraPreviewHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } }