diff options
author | Jay Wang <jaywang@codeaurora.org> | 2016-05-09 18:35:53 -0700 |
---|---|---|
committer | Steve Kondik <steve@cyngn.com> | 2016-08-21 18:45:51 -0700 |
commit | 1fea7d5bb3dd45caf29e90be2e9eae2646567a10 (patch) | |
tree | bd3059bba91264f649251456ce06789e38667818 /src | |
parent | 67f8bccf87818e7ea124fa733c56894030ee5951 (diff) | |
download | android_packages_apps_Snap-1fea7d5bb3dd45caf29e90be2e9eae2646567a10.tar.gz android_packages_apps_Snap-1fea7d5bb3dd45caf29e90be2e9eae2646567a10.tar.bz2 android_packages_apps_Snap-1fea7d5bb3dd45caf29e90be2e9eae2646567a10.zip |
SnapdragonCamera: Enable jpeg encoding via reprocess
Enable JPEG encoding via reprocess request for
ClearSight routine.
Add support for dumping images in NV21 format using
persist.camera.cs.dumpyuv
CRs-Fixed: 993611
Change-Id: I51ff59ec45bb37059a16197186a9f90bc52554f1
Diffstat (limited to 'src')
4 files changed, 387 insertions, 211 deletions
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java index 6bb16950f..90e1794ac 100644 --- a/src/com/android/camera/CaptureModule.java +++ b/src/com/android/camera/CaptureModule.java @@ -750,12 +750,11 @@ public class CaptureModule implements CameraModule, PhotoController, } else { // No Clearsight captureBuilder = mCameraDevice[id].createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); - - // Orientation - int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation(); - captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); } + // Orientation + int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation(); + captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); captureBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); captureBuilder.addTarget(getPreviewSurface(id)); captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, mControlAFMode); @@ -855,7 +854,8 @@ public class CaptureModule implements CameraModule, PhotoController, Size largest = Collections.max( Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)), new CompareSizesByArea()); - ClearSightImageProcessor.getInstance().init(largest.getWidth(), largest.getHeight(), mActivity); + ClearSightImageProcessor.getInstance().init( + largest.getWidth(), largest.getHeight(), mActivity, mOnMediaSavedListener); ClearSightImageProcessor.getInstance().setCallback(this); } else { // No Clearsight @@ -1345,6 +1345,10 @@ public class CaptureModule implements CameraModule, PhotoController, public void onMediaSaveServiceConnected(MediaSaveService s) { if (mFirstTimeInitialized) { s.setListener(this); + ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CLEARSIGHT); + if(pref.getValue().equals(mActivity.getString(R.string.pref_camera_clearsight_value_on))) { + ClearSightImageProcessor.getInstance().setMediaSaveService(s); + } } } @@ -1655,18 +1659,8 @@ public class CaptureModule implements CameraModule, PhotoController, } @Override - public void onClearSightSuccess(ClearsightImage csImage, YuvImage bayer, YuvImage mono) { - Log.d(TAG, "reprocess - processClearSight success"); - mNamedImages.nameNewImage(System.currentTimeMillis()); - NamedEntity name = mNamedImages.getNextNameEntity(); - String title = (name == null) ? null : name.title; - long date = (name == null) ? -1 : name.date; - - mActivity.getMediaSaveService().addMpoImage( - csImage, bayer, mono, null, null, title, - date, null, 0, mOnMediaSavedListener, mContentResolver, - "jpeg"); - + public void onClearSightSuccess() { + Log.d(TAG, "onClearSightSuccess"); mActivity.runOnUiThread(new Runnable() { @Override public void run() { @@ -1680,21 +1674,8 @@ public class CaptureModule implements CameraModule, PhotoController, } @Override - public void onClearSightFailure(YuvImage bayer, YuvImage mono) { - if(bayer != null && mono != null) { - Log.d(TAG, "reprocess - processClearSight fail"); - mNamedImages.nameNewImage(System.currentTimeMillis()); - NamedEntity name = mNamedImages.getNextNameEntity(); - String title = (name == null) ? null : name.title; - long date = (name == null) ? -1 : name.date; - - Log.d(TAG, "reprocess - saving with bayer + mono mpo"); - - mActivity.getMediaSaveService().addMpoImage(null, - bayer, mono, null, null, title, date, null, 0, - mOnMediaSavedListener, mContentResolver, "jpeg"); - } - + public void onClearSightFailure() { + Log.d(TAG, "onClearSightFailure"); mActivity.runOnUiThread(new Runnable() { @Override public void run() { @@ -1706,14 +1687,4 @@ public class CaptureModule implements CameraModule, PhotoController, unlockFocus(BAYER_ID); unlockFocus(MONO_ID); } - - @Override - public CameraCaptureSession onReprocess(boolean bayer) { - return mCaptureSession[bayer?BAYER_ID:MONO_ID]; - } - - @Override - public MediaSaveService getMediaSaveService() { - return mActivity.getMediaSaveService(); - } } diff --git a/src/com/android/camera/MediaSaveService.java b/src/com/android/camera/MediaSaveService.java index 3c5dbe586..58ebc11b4 100644 --- a/src/com/android/camera/MediaSaveService.java +++ b/src/com/android/camera/MediaSaveService.java @@ -16,7 +16,6 @@ package com.android.camera; -import java.io.ByteArrayOutputStream; import java.io.File; import java.nio.ByteOrder; @@ -25,9 +24,6 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; import android.graphics.BitmapFactory; -import android.graphics.Rect; -import android.graphics.YuvImage; -import android.hardware.camera2.TotalCaptureResult; import android.location.Location; import android.net.Uri; import android.os.AsyncTask; @@ -36,13 +32,7 @@ import android.os.IBinder; import android.provider.MediaStore.Video; import android.util.Log; -import com.android.camera.PhotoModule; import com.android.camera.exif.ExifInterface; - -import java.io.File; - -import org.codeaurora.snapcam.filter.ClearSightNativeEngine.ClearsightImage; - import com.android.camera.mpo.MpoData; import com.android.camera.mpo.MpoImageData; import com.android.camera.mpo.MpoInterface; @@ -99,9 +89,9 @@ public class MediaSaveService extends Service { return (mMemoryUse >= SAVE_TASK_MEMORY_LIMIT); } - public void addMpoImage(final ClearsightImage csImage, - final YuvImage bayerImg, final YuvImage monoImg, - TotalCaptureResult bayerResult, TotalCaptureResult monoResult, + public void addMpoImage(final byte[] csImage, + final byte[] bayerImg, final byte[] monoImg, + int width, int height, String title, long date, Location loc, int orientation, OnMediaSavedListener l, ContentResolver resolver, String pictureFormat) { @@ -111,12 +101,12 @@ public class MediaSaveService extends Service { } MpoSaveTask t = new MpoSaveTask(csImage, bayerImg, monoImg, - bayerResult, monoResult, title, date, loc, orientation, l, + width, height, title, date, loc, orientation, l, resolver, pictureFormat); long size = (csImage == null ? 0 - : csImage.getDataLength()) - + bayerImg.getYuvData().length + monoImg.getYuvData().length; + : csImage.length) + + bayerImg.length + monoImg.length; mMemoryUse += size; if (isQueueFull()) { onQueueFull(); @@ -179,23 +169,20 @@ public class MediaSaveService extends Service { } private class MpoSaveTask extends AsyncTask<Void, Void, Uri> { - private ClearsightImage csImage; - private YuvImage bayerImage; - private YuvImage monoImage; + private byte[] csImage; + private byte[] bayerImage; + private byte[] monoImage; private String title; private long date; private Location loc; private int width, height; private int orientation; - private TotalCaptureResult bayerResult; - private TotalCaptureResult monoResult; private ContentResolver resolver; private OnMediaSavedListener listener; private String pictureFormat; - public MpoSaveTask(ClearsightImage csImage, YuvImage bayerImg, - YuvImage monoImg, TotalCaptureResult bayerResult, - TotalCaptureResult monoResult, String title, long date, + public MpoSaveTask(byte[] csImage, byte[] bayerImg, + byte[] monoImg, int width, int height, String title, long date, Location loc, int orientation, OnMediaSavedListener listener, ContentResolver resolver, String pictureFormat) { this.csImage = csImage; @@ -204,11 +191,9 @@ public class MediaSaveService extends Service { this.title = title; this.date = date; this.loc = loc; - this.width = bayerImg.getWidth(); - this.height = bayerImg.getHeight(); + this.width = width; + this.height = height; this.orientation = orientation; - this.bayerResult = bayerResult; - this.monoResult = monoResult; this.resolver = resolver; this.listener = listener; this.pictureFormat = pictureFormat; @@ -218,23 +203,17 @@ public class MediaSaveService extends Service { protected Uri doInBackground(Void... v) { // encode jpeg and add exif for all images MpoData mpo = new MpoData(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - bayerImage.compressToJpeg(new Rect(0, 0, bayerImage.getWidth(), - bayerImage.getHeight()), 100, baos); - MpoImageData bayer = new MpoImageData(baos.toByteArray(), + MpoImageData bayer = new MpoImageData(bayerImage, ByteOrder.BIG_ENDIAN); - baos.reset(); - monoImage.compressToJpeg(new Rect(0, 0, monoImage.getWidth(), - monoImage.getHeight()), 100, baos); - MpoImageData mono = new MpoImageData(baos.toByteArray(), + MpoImageData mono = new MpoImageData(monoImage, ByteOrder.BIG_ENDIAN); if (csImage == null) { mpo.addAuxiliaryMpoImage(mono); mpo.setPrimaryMpoImage(bayer); } else { - MpoImageData cs = new MpoImageData(csImage.compressToJpeg(), + MpoImageData cs = new MpoImageData(csImage, ByteOrder.BIG_ENDIAN); mpo.addAuxiliaryMpoImage(bayer); @@ -260,9 +239,9 @@ public class MediaSaveService extends Service { listener.onMediaSaved(uri); boolean previouslyFull = isQueueFull(); long size = (csImage == null ? 0 - : csImage.getDataLength()) - + bayerImage.getYuvData().length - + monoImage.getYuvData().length; + : csImage.length) + + bayerImage.length + + monoImage.length; mMemoryUse -= size; if (isQueueFull() != previouslyFull) onQueueAvailable(); diff --git a/src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java b/src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java index 141d8e412..c33726322 100644 --- a/src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java +++ b/src/org/codeaurora/snapcam/filter/ClearSightImageProcessor.java @@ -30,13 +30,13 @@ package org.codeaurora.snapcam.filter; import java.io.ByteArrayOutputStream; +import java.io.File; import java.nio.ByteBuffer; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import org.codeaurora.snapcam.filter.ClearSightNativeEngine.CamSystemCalibrationData; -import org.codeaurora.snapcam.filter.ClearSightNativeEngine.ClearsightImage; import android.content.Context; import android.graphics.ImageFormat; @@ -66,14 +66,18 @@ import android.util.Log; import android.view.Surface; import com.android.camera.MediaSaveService; +import com.android.camera.MediaSaveService.OnMediaSavedListener; import com.android.camera.PhotoModule.NamedImages; import com.android.camera.PhotoModule.NamedImages.NamedEntity; +import com.android.camera.SDCard; +import com.android.camera.Storage; public class ClearSightImageProcessor { private static final String TAG = "ClearSightImageProcessor"; private static final String PERSIST_TIMESTAMP_LIMIT_KEY = "persist.camera.cs.threshold"; private static final String PERSIST_BURST_COUNT_KEY = "persist.camera.cs.burstcount"; private static final String PERSIST_DUMP_FRAMES_KEY = "persist.camera.cs.dumpframes"; + private static final String PERSIST_DUMP_YUV_KEY = "persist.camera.cs.dumpyuv"; private static final long DEFAULT_TIMESTAMP_THRESHOLD_MS = 10; private static final int DEFAULT_IMAGES_TO_BURST = 5; @@ -93,18 +97,23 @@ public class ClearSightImageProcessor { private NamedImages mNamedImages; private ImageReader[] mImageReader = new ImageReader[NUM_CAM]; - private ImageReader[] mReprocessImageReader = new ImageReader[NUM_CAM]; + private ImageReader[] mEncodeImageReader = new ImageReader[NUM_CAM]; private ImageWriter[] mImageWriter = new ImageWriter[NUM_CAM]; private ImageProcessHandler mImageProcessHandler; - private ImageReprocessHandler mImageReprocessHandler; + private ImageEncodeHandler mImageEncodeHandler; private HandlerThread mImageProcessThread; - private HandlerThread mImageReprocessThread; + private HandlerThread mImageEncodeThread; private Callback mCallback; + private CameraCaptureSession[] mCaptureSessions = new CameraCaptureSession[NUM_CAM]; + private MediaSaveService mMediaSaveService; + private OnMediaSavedListener mMediaSavedListener; + private long mTimestampThresholdNs; private int mNumBurstCount; private boolean mDumpImages; + private boolean mDumpYUV; private static ClearSightImageProcessor mInstance; @@ -119,6 +128,9 @@ public class ClearSightImageProcessor { mDumpImages = SystemProperties.getBoolean(PERSIST_DUMP_FRAMES_KEY, false); Log.d(TAG, "mDumpImages: " + mDumpImages); + + mDumpYUV = SystemProperties.getBoolean(PERSIST_DUMP_YUV_KEY, false); + Log.d(TAG, "mDumpYUV: " + mDumpYUV); } public static void createInstance() { @@ -135,20 +147,21 @@ public class ClearSightImageProcessor { return mInstance; } - public void init(int width, int height, Context context) { + public void init(int width, int height, Context context, OnMediaSavedListener mediaListener) { mImageProcessThread = new HandlerThread("CameraImageProcess"); mImageProcessThread.start(); - mImageReprocessThread = new HandlerThread("CameraImageReprocess"); - mImageReprocessThread.start(); + mImageEncodeThread = new HandlerThread("CameraImageEncode"); + mImageEncodeThread.start(); mImageProcessHandler = new ImageProcessHandler(mImageProcessThread.getLooper()); - mImageReprocessHandler = new ImageReprocessHandler(mImageReprocessThread.getLooper()); + mImageEncodeHandler = new ImageEncodeHandler(mImageEncodeThread.getLooper()); mImageReader[CAM_TYPE_BAYER] = createImageReader(CAM_TYPE_BAYER, width, height); mImageReader[CAM_TYPE_MONO] = createImageReader(CAM_TYPE_MONO, width, height); - mReprocessImageReader[CAM_TYPE_BAYER] = createReprocImageReader(CAM_TYPE_BAYER, width, height); - mReprocessImageReader[CAM_TYPE_MONO] = createReprocImageReader(CAM_TYPE_MONO, width, height); + mEncodeImageReader[CAM_TYPE_BAYER] = createEncodeImageReader(CAM_TYPE_BAYER, width, height); + mEncodeImageReader[CAM_TYPE_MONO] = createEncodeImageReader(CAM_TYPE_MONO, width, height); + mMediaSavedListener = mediaListener; CameraManager cm = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); try { CameraCharacteristics cc = cm.getCameraCharacteristics("0"); @@ -165,9 +178,9 @@ public class ClearSightImageProcessor { mImageReader[i].close(); mImageReader[i] = null; } - if (null != mReprocessImageReader[i]) { - mReprocessImageReader[i].close(); - mReprocessImageReader[i] = null; + if (null != mEncodeImageReader[i]) { + mEncodeImageReader[i].close(); + mEncodeImageReader[i] = null; } if (null != mImageWriter[i]) { mImageWriter[i].close(); @@ -187,23 +200,20 @@ public class ClearSightImageProcessor { } } - if(mImageReprocessThread != null) { - mImageReprocessThread.quitSafely(); - - try { - mImageReprocessThread.join(); - mImageReprocessThread = null; - mImageReprocessHandler = null; - } catch (InterruptedException e) { - e.printStackTrace(); - } - } + mCaptureSessions[CAM_TYPE_MONO] = null; + mCaptureSessions[CAM_TYPE_BAYER] = null; + mMediaSaveService = null; + mMediaSavedListener = null; } public void setCallback(Callback callback) { mCallback = callback; } + public void setMediaSaveService(MediaSaveService service) { + mMediaSaveService = service; + } + public void createCaptureSession(boolean bayer, CameraDevice device, List<Surface> surfaces, CameraCaptureSession.StateCallback captureSessionCallback) throws CameraAccessException { @@ -211,7 +221,7 @@ public class ClearSightImageProcessor { int cam = bayer?CAM_TYPE_BAYER:CAM_TYPE_MONO; surfaces.add(mImageReader[cam].getSurface()); - surfaces.add(mReprocessImageReader[cam].getSurface()); + surfaces.add(mEncodeImageReader[cam].getSurface()); // Here, we create a CameraCaptureSession for camera preview. device.createReprocessableCaptureSession( new InputConfiguration(mImageReader[cam].getWidth(), @@ -222,6 +232,7 @@ public class ClearSightImageProcessor { public void onCaptureSessionConfigured(boolean bayer, CameraCaptureSession session) { Log.d(TAG, "onCaptureSessionConfigured: " + bayer); + mCaptureSessions[bayer?CAM_TYPE_BAYER:CAM_TYPE_MONO] = session; mImageWriter[bayer?CAM_TYPE_BAYER:CAM_TYPE_MONO] = ImageWriter.newInstance(session.getInputSurface(), mNumBurstCount); } @@ -230,9 +241,6 @@ public class ClearSightImageProcessor { Log.d(TAG, "createCaptureRequest"); CaptureRequest.Builder builder = device.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG); - // Orientation - // int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation(); - // captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); return builder; } @@ -276,7 +284,7 @@ public class ClearSightImageProcessor { burstList.add(request); } - mImageProcessHandler.obtainMessage(MSG_START_CAPTURE, cam, burstList.size()).sendToTarget(); + mImageProcessHandler.obtainMessage(MSG_START_CAPTURE, cam, burstList.size(), ProcessState.CAPTURE).sendToTarget(); session.captureBurst(burstList, captureCallback, captureCallbackHandler); } @@ -295,14 +303,14 @@ public class ClearSightImageProcessor { return reader; } - private ImageReader createReprocImageReader(final int cam, int width, int height) { + private ImageReader createEncodeImageReader(final int cam, int width, int height) { ImageReader reader = ImageReader.newInstance(width, height, - ImageFormat.YUV_420_888, mNumBurstCount); + ImageFormat.JPEG, mNumBurstCount); reader.setOnImageAvailableListener(new OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { - Log.d(TAG, "reprocessed image available for cam: " + cam); - mImageReprocessHandler.obtainMessage( + Log.d(TAG, "jpeg image available for cam: " + cam); + mImageEncodeHandler.obtainMessage( MSG_NEW_IMG, cam, 0, reader.acquireNextImage()).sendToTarget(); } }, null); @@ -311,10 +319,8 @@ public class ClearSightImageProcessor { } public interface Callback { - public void onClearSightSuccess(ClearsightImage csImage, YuvImage bayer, YuvImage mono); - public void onClearSightFailure(YuvImage bayer, YuvImage mono); - public CameraCaptureSession onReprocess(boolean bayer); - public MediaSaveService getMediaSaveService(); + public void onClearSightSuccess(); + public void onClearSightFailure(); } private static class ReprocessableImage { @@ -327,6 +333,12 @@ public class ClearSightImageProcessor { } } + private enum ProcessState { + IDLE, + CAPTURE, + REPROCESS + }; + private class ImageProcessHandler extends Handler { private ArrayDeque<ReprocessableImage> mBayerFrames = new ArrayDeque<ReprocessableImage>( mNumBurstCount); @@ -340,9 +352,11 @@ public class ClearSightImageProcessor { mNumBurstCount); private ArrayDeque<Image> mMonoImages = new ArrayDeque<Image>( mNumBurstCount); + private ReprocessableImage mClearSightFrame; private int[] mNumImagesToProcess = new int[NUM_CAM]; + private ProcessState mState = ProcessState.IDLE; - public ImageProcessHandler(Looper looper) { + ImageProcessHandler(Looper looper) { super(looper); } @@ -351,27 +365,31 @@ public class ClearSightImageProcessor { switch (msg.what) { case MSG_START_CAPTURE: mNumImagesToProcess[msg.arg1] = msg.arg2; + mState = (ProcessState)msg.obj; break; case MSG_NEW_IMG: case MSG_NEW_RESULT: - processNewEvent(msg); + if(mState == ProcessState.CAPTURE) + processNewCaptureEvent(msg); + else + processNewReprocessEvent(msg); break; } } - private void processNewEvent(Message msg) { + private void processNewCaptureEvent(Message msg) { ArrayDeque<Image> imageQueue; ArrayDeque<TotalCaptureResult> resultQueue; - ArrayDeque<ReprocessableImage> reprocQueue; + ArrayDeque<ReprocessableImage> frameQueue; // push image onto queue if (msg.arg1 == CAM_TYPE_BAYER) { imageQueue = mBayerImages; resultQueue = mBayerCaptureResults; - reprocQueue = mBayerFrames; + frameQueue = mBayerFrames; } else { imageQueue = mMonoImages; resultQueue = mMonoCaptureResults; - reprocQueue = mMonoFrames; + frameQueue = mMonoFrames; } if(msg.what == MSG_NEW_IMG) { @@ -393,7 +411,7 @@ public class ClearSightImageProcessor { if (!imageQueue.isEmpty() && !resultQueue.isEmpty()) { Image headImage = imageQueue.poll(); TotalCaptureResult headResult = resultQueue.poll(); - reprocQueue.add(new ReprocessableImage(headImage, headResult)); + frameQueue.add(new ReprocessableImage(headImage, headResult)); mNumImagesToProcess[msg.arg1]--; checkForValidFramePair(); } @@ -470,7 +488,7 @@ public class ClearSightImageProcessor { Log.d(TAG, "processReprocess - frames are empty"); releaseBayerFrames(); releaseMonoFrames(); - mCallback.onClearSightFailure(null, null); + mCallback.onClearSightFailure(); return; } else { int frameCount = Math.min(mMonoFrames.size(), mBayerFrames.size()); @@ -484,7 +502,7 @@ public class ClearSightImageProcessor { } private void sendReprocessRequests(final int camId, int frameCount) { - CameraCaptureSession session = mCallback.onReprocess(camId == CAM_TYPE_BAYER); + CameraCaptureSession session = mCaptureSessions[camId]; CameraDevice device = session.getDevice(); try { @@ -505,8 +523,11 @@ public class ClearSightImageProcessor { CaptureRequest.Builder reprocRequest = device .createReprocessCaptureRequest(reprocImg.mCaptureResult); - reprocRequest.addTarget(mReprocessImageReader[camId] + reprocRequest.addTarget(mImageReader[camId] .getSurface()); + if(reprocRequests.size() == 0) { + reprocRequest.setTag(new Object()); + } reprocRequests.add(reprocRequest.build()); mImageWriter[camId].queueInputImage(reprocImg.mImage); @@ -521,8 +542,8 @@ public class ClearSightImageProcessor { } } - mImageReprocessHandler.obtainMessage(MSG_START_CAPTURE, camId, - reprocRequests.size()).sendToTarget(); + mImageProcessHandler.obtainMessage(MSG_START_CAPTURE, camId, + reprocRequests.size(), ProcessState.REPROCESS).sendToTarget(); session.captureBurst(reprocRequests, new CaptureCallback() { @Override @@ -533,6 +554,11 @@ public class ClearSightImageProcessor { super.onCaptureCompleted(session, request, result); Log.d(TAG, "reprocess - onCaptureCompleted: " + camId); + if(request.getTag() != null) { + mImageProcessHandler.obtainMessage( + MSG_NEW_RESULT, camId, 0, result) + .sendToTarget(); + } } @Override @@ -543,7 +569,7 @@ public class ClearSightImageProcessor { super.onCaptureFailed(session, request, failure); Log.d(TAG, "reprocess - onCaptureFailed: " + camId); - mImageReprocessHandler.obtainMessage( + mImageProcessHandler.obtainMessage( MSG_NEW_RESULT, camId, 1) .sendToTarget(); } @@ -552,29 +578,8 @@ public class ClearSightImageProcessor { e.printStackTrace(); } } - }; - - private class ImageReprocessHandler extends Handler { - private int[] mNumImagesToProcess = new int[NUM_CAM]; - - public ImageReprocessHandler(Looper looper) { - super(looper); - } - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_START_CAPTURE: - mNumImagesToProcess[msg.arg1] = msg.arg2; - break; - case MSG_NEW_IMG: - case MSG_NEW_RESULT: - processNewEvent(msg); - break; - } - } - - private void processNewEvent(Message msg) { + private void processNewReprocessEvent(Message msg) { boolean isBayer = (msg.arg1 == CAM_TYPE_BAYER); if(msg.what == MSG_NEW_IMG) { @@ -582,7 +587,10 @@ public class ClearSightImageProcessor { Log.d(TAG, "reprocess - processNewImg"); if(mDumpImages) { - saveDebugImage(mCallback.getMediaSaveService(), image, true); + saveDebugImageAsJpeg(mMediaSaveService, image, isBayer); + if(mDumpYUV) { + saveDebugImageAsNV21(image, isBayer); + } } if (!ClearSightNativeEngine.getInstance() @@ -601,13 +609,24 @@ public class ClearSightImageProcessor { } else if (msg.arg2 == 1) { // capture failed mNumImagesToProcess[msg.arg1]--; + } else { + Log.d(TAG, "reprocess - processNewResult: " + msg.arg1); + if (ClearSightNativeEngine.getInstance() + .getReferenceResult(isBayer) == null) { + // reference not yet set + Log.d(TAG, "reprocess - setReferenceResult: " + msg.obj); + ClearSightNativeEngine.getInstance().setReferenceResult(isBayer, + (TotalCaptureResult)msg.obj); + } } Log.d(TAG, "reprocess - processNewEvent, cam: " + msg.arg1 + " count: " + mNumImagesToProcess[msg.arg1]); if (mNumImagesToProcess[CAM_TYPE_BAYER] == 0 - && mNumImagesToProcess[CAM_TYPE_MONO] == 0) { + && mNumImagesToProcess[CAM_TYPE_MONO] == 0 + && ClearSightNativeEngine.getInstance().getReferenceResult(true) != null + && ClearSightNativeEngine.getInstance().getReferenceResult(false) != null) { processClearSight(); } } @@ -617,35 +636,197 @@ public class ClearSightImageProcessor { + mNumImagesToProcess[CAM_TYPE_BAYER] + " mono count: " + mNumImagesToProcess[CAM_TYPE_MONO]); - if(mCallback != null) { - ClearSightNativeEngine.ClearsightImage csImage = ClearSightNativeEngine - .getInstance().processImage(); - - if(csImage != null) { - Log.d(TAG, "reprocess - processClearSight, roiRect: " - + csImage.getRoiRect().toString()); - mCallback.onClearSightSuccess(csImage, - createYuvImage(ClearSightNativeEngine.getInstance().getReferenceImage(true)), - createYuvImage(ClearSightNativeEngine.getInstance().getReferenceImage(false))); - } else { - mCallback.onClearSightFailure( - createYuvImage(ClearSightNativeEngine.getInstance().getReferenceImage(true)), - createYuvImage(ClearSightNativeEngine.getInstance().getReferenceImage(false))); - } + ClearSightNativeEngine.ClearsightImage csImage = ClearSightNativeEngine + .getInstance().processImage(); + + if(csImage != null) { + Log.d(TAG, "reprocess - processClearSight, roiRect: " + + csImage.getRoiRect().toString()); + + Image encodeImage = mImageWriter[CAM_TYPE_BAYER].dequeueInputImage(); + encodeImage.setCropRect(csImage.getRoiRect()); + encodeImage.setTimestamp( + ClearSightNativeEngine.getInstance().getReferenceImage(true).getTimestamp()); + Plane[] planes = encodeImage.getPlanes(); + planes[0].getBuffer().put(csImage.mYplane); + planes[2].getBuffer().put(csImage.mVUplane); + + mClearSightFrame = new ReprocessableImage(encodeImage, + ClearSightNativeEngine.getInstance().getReferenceResult(true)); + if(mCallback != null) + mCallback.onClearSightSuccess(); + } else { + mClearSightFrame = null; + if(mCallback != null) + mCallback.onClearSightFailure(); } + sendEncodeRequests(); ClearSightNativeEngine.getInstance().reset(); + mClearSightFrame = null; + mState = ProcessState.IDLE; + } + + private void sendEncodeRequests() { + mImageEncodeHandler.obtainMessage( + MSG_START_CAPTURE, (mClearSightFrame != null)?1:0, 0).sendToTarget(); + + // First Mono + CameraCaptureSession session = mCaptureSessions[CAM_TYPE_MONO]; + sendReprocessRequest(session, + new ReprocessableImage( + ClearSightNativeEngine.getInstance().getReferenceImage(false), + ClearSightNativeEngine.getInstance().getReferenceResult(false)), + CAM_TYPE_MONO); + + // bayer + session = mCaptureSessions[CAM_TYPE_BAYER]; + sendReprocessRequest(session, + new ReprocessableImage( + ClearSightNativeEngine.getInstance().getReferenceImage(true), + ClearSightNativeEngine.getInstance().getReferenceResult(true)), + CAM_TYPE_BAYER); + + // clearsight + if(mClearSightFrame != null) + sendReprocessRequest(session, mClearSightFrame, CAM_TYPE_BAYER); + } + + private void sendReprocessRequest(CameraCaptureSession session, ReprocessableImage image, final int camType) { + CameraDevice device = session.getDevice(); + + try { + CaptureRequest.Builder reprocRequest = device + .createReprocessCaptureRequest(image.mCaptureResult); + reprocRequest.addTarget(mEncodeImageReader[camType] + .getSurface()); + reprocRequest.set(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE, + CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF); + reprocRequest.set(CaptureRequest.EDGE_MODE, + CaptureRequest.EDGE_MODE_OFF); + reprocRequest.set(CaptureRequest.NOISE_REDUCTION_MODE, + CaptureRequest.NOISE_REDUCTION_MODE_OFF); + + mImageWriter[camType].queueInputImage(image.mImage); + + session.capture(reprocRequest.build(), + new CaptureCallback() { + @Override + public void onCaptureCompleted( + CameraCaptureSession session, + CaptureRequest request, + TotalCaptureResult result) { + super.onCaptureCompleted(session, request, result); + Log.d(TAG, "encode - onCaptureCompleted: " + camType); + mImageEncodeHandler.obtainMessage( + MSG_NEW_RESULT, camType, 0, result) + .sendToTarget(); + } + + @Override + public void onCaptureFailed( + CameraCaptureSession session, + CaptureRequest request, + CaptureFailure failure) { + super.onCaptureFailed(session, request, failure); + Log.d(TAG, "encode - onCaptureFailed: " + camType); + mImageEncodeHandler.obtainMessage( + MSG_NEW_RESULT, camType, 1) + .sendToTarget(); + } + }, null); + } catch (CameraAccessException e) { + e.printStackTrace(); + } } }; - public void saveDebugImage(MediaSaveService service, byte[] data, - int width, int height, boolean isReproc) { + private class ImageEncodeHandler extends Handler { + private boolean mClearsightEncode; + private Image mMonoImage; + private Image mBayerImage; + private Image mClearSightImage; + + public ImageEncodeHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_START_CAPTURE: + mClearsightEncode = (msg.arg1 == 1); + break; + case MSG_NEW_IMG: + case MSG_NEW_RESULT: + processNewEvent(msg); + break; + } + } + + private void processNewEvent(Message msg) { + if(msg.what == MSG_NEW_IMG) { + Log.d(TAG, "processNewEncodeEvent - newImg: " + msg.arg1); + if(msg.arg1 == CAM_TYPE_MONO) { + mMonoImage = (Image)msg.obj; + } else if(mBayerImage == null){ + mBayerImage = (Image)msg.obj; + } else { + mClearSightImage = (Image)msg.obj; + } + } else if (msg.arg2 == 0) { + Log.d(TAG, "processNewEncodeEvent - newResult: " + msg.arg1); + } else { + Log.d(TAG, "processNewEncodeEvent - newFailure: " + msg.arg1); + } + if(mMonoImage != null && mBayerImage != null + && (!mClearsightEncode || + (mClearsightEncode && mClearSightImage != null))) { + saveMpoImage(); + } + } + + private void saveMpoImage() { + mNamedImages.nameNewImage(System.currentTimeMillis()); + NamedEntity name = mNamedImages.getNextNameEntity(); + String title = (name == null) ? null : name.title; + long date = (name == null) ? -1 : name.date; + int width = mBayerImage.getWidth(); + int height = mBayerImage.getHeight(); + + if(mClearsightEncode) { + width = mClearSightImage.getWidth(); + height = mClearSightImage.getHeight(); + } + + mMediaSaveService.addMpoImage( + getJpegData(mClearSightImage), + getJpegData(mBayerImage), + getJpegData(mMonoImage), width, height, title, + date, null, 0, mMediaSavedListener, + mMediaSaveService.getContentResolver(), "jpeg"); + + mBayerImage.close(); + mBayerImage = null; + mMonoImage.close(); + mMonoImage = null; + if(mClearSightImage != null) { + mClearSightImage.close(); + mClearSightImage = null; + } + } + } + + public void saveDebugImageAsJpeg(MediaSaveService service, byte[] data, + int width, int height, boolean isBayer) { mNamedImages.nameNewImage(System.currentTimeMillis()); NamedEntity name = mNamedImages.getNextNameEntity(); String title = (name == null) ? null : name.title; long date = (name == null) ? -1 : name.date; - if (isReproc) { - title += "_reproc"; + if (isBayer) { + title += "_bayer"; + } else { + title += "_mono"; } service.addImage(data, title, date, null, @@ -653,17 +834,43 @@ public class ClearSightImageProcessor { service.getContentResolver(), "jpeg"); } - public void saveDebugImage(MediaSaveService service, YuvImage image, boolean isReproc) { + public void saveDebugImageAsJpeg(MediaSaveService service, YuvImage image, boolean isBayer) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compressToJpeg( new Rect(0, 0, image.getWidth(), image.getHeight()), 100, baos); - saveDebugImage(service, baos.toByteArray(), image.getWidth(), image.getHeight(), - isReproc); + saveDebugImageAsJpeg(service, baos.toByteArray(), image.getWidth(), image.getHeight(), + isBayer); + } + + public void saveDebugImageAsJpeg(MediaSaveService service, Image image, boolean isBayer) { + if(image.getFormat() == ImageFormat.YUV_420_888) + saveDebugImageAsJpeg(service, createYuvImage(image), isBayer); + else if (image.getFormat() == ImageFormat.JPEG) { + saveDebugImageAsJpeg(service, getJpegData(image), image.getWidth(), image.getHeight(), isBayer); + } } - public void saveDebugImage(MediaSaveService service, Image image, boolean isReproc) { - saveDebugImage(service, createYuvImage(image), isReproc); + public void saveDebugImageAsNV21(Image image, boolean isBayer) { + if(image.getFormat() != ImageFormat.YUV_420_888) { + Log.d(TAG, "saveDebugImageAsNV21 - invalid param"); + } + + mNamedImages.nameNewImage(System.currentTimeMillis()); + NamedEntity name = mNamedImages.getNextNameEntity(); + StringBuilder pathSB = (name == null) ? new StringBuilder() : new StringBuilder(name.title); + pathSB.append("_" + image.getWidth() + "x" + image.getHeight()); + pathSB.append("_NV21"); + + if (isBayer) { + pathSB.append("_bayer"); + } else { + pathSB.append("_mono"); + } + + YuvImage yuv = createYuvImage(image); + String path = Storage.generateFilepath(pathSB.toString(), "yuv"); + Storage.writeFile(path, yuv.getYuvData(), null, "yuv"); } public YuvImage createYuvImage(Image image) { @@ -687,4 +894,19 @@ public class ClearSightImageProcessor { return new YuvImage(data, ImageFormat.NV21, image.getWidth(), image.getHeight(), strides); } + + public byte[] getJpegData(Image image) { + if (image == null) { + Log.d(TAG, "getJpegData - invalid param"); + return null; + } + Plane[] planes = image.getPlanes(); + ByteBuffer buffer = planes[0].getBuffer(); + int size = buffer.capacity(); + byte[] data = new byte[size]; + buffer.rewind(); + buffer.get(data, 0, size); + + return data; + } } diff --git a/src/org/codeaurora/snapcam/filter/ClearSightNativeEngine.java b/src/org/codeaurora/snapcam/filter/ClearSightNativeEngine.java index c79d15a84..0fc23f1bf 100644 --- a/src/org/codeaurora/snapcam/filter/ClearSightNativeEngine.java +++ b/src/org/codeaurora/snapcam/filter/ClearSightNativeEngine.java @@ -29,15 +29,13 @@ package org.codeaurora.snapcam.filter; -import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.List; -import android.graphics.ImageFormat; import android.graphics.Rect; -import android.graphics.YuvImage; +import android.hardware.camera2.TotalCaptureResult; import android.media.Image; import android.media.Image.Plane; import android.util.Log; @@ -62,11 +60,13 @@ public class ClearSightNativeEngine { private static final int VU_PLANE = 2; private static boolean mLibLoaded; - private static CamSystemCalibrationData mOtpCalibData; + private static byte[] mOtpCalibData; private static ClearSightNativeEngine mInstance; private Image mRefColorImage; private Image mRefMonoImage; + private TotalCaptureResult mRefColorResult; + private TotalCaptureResult mRefMonoResult; private ArrayList<SourceImage> mSrcColor = new ArrayList<SourceImage>(); private ArrayList<SourceImage> mSrcMono = new ArrayList<SourceImage>(); @@ -85,7 +85,9 @@ public class ClearSightNativeEngine { } public static void setOtpCalibData(CamSystemCalibrationData calibData) { - mOtpCalibData = calibData; + String calibStr = calibData.toString(); + Log.d(TAG, "OTP calibration data: \n" + calibStr); + mOtpCalibData = calibStr.getBytes(); } public boolean isLibLoaded() { @@ -97,6 +99,23 @@ public class ClearSightNativeEngine { mSrcMono.clear(); setReferenceColorImage(null); setReferenceMonoImage(null); + setReferenceColorResult(null); + setReferenceMonoResult(null); + } + + public void setReferenceResult(boolean color, TotalCaptureResult result) { + if (color) + setReferenceColorResult(result); + else + setReferenceMonoResult(result); + } + + private void setReferenceColorResult(TotalCaptureResult result) { + mRefColorResult = result; + } + + private void setReferenceMonoResult(TotalCaptureResult result) { + mRefMonoResult = result; } public void setReferenceImage(boolean color, Image image) { @@ -145,6 +164,10 @@ public class ClearSightNativeEngine { return color ? mRefColorImage : mRefMonoImage; } + public TotalCaptureResult getReferenceResult(boolean color) { + return color ? mRefColorResult : mRefMonoResult; + } + public boolean registerImage(boolean color, Image image) { List<SourceImage> sourceImages = color?mSrcColor:mSrcMono; if (sourceImages.isEmpty()) { @@ -229,30 +252,20 @@ public class ClearSightNativeEngine { Log.d(TAG, "processImage - dst size - y: " + dstY.capacity() + " vu: " + dstVU.capacity()); - String otp_string = mOtpCalibData.toString(); - Log.d(TAG, "processImage - otp_calib: " + otp_string); - boolean result = nativeClearSightProcess(numImages, srcColorY, srcColorVU, metadataColor, mRefColorImage.getWidth(), mRefColorImage.getHeight(), colorPlanes[Y_PLANE].getRowStride(), colorPlanes[VU_PLANE].getRowStride(), srcMonoY, metadataMono, mRefMonoImage.getWidth(), mRefMonoImage.getHeight(), - monoPlanes[Y_PLANE].getRowStride(), otp_string.getBytes(), dstY, dstVU, + monoPlanes[Y_PLANE].getRowStride(), mOtpCalibData, dstY, dstVU, colorPlanes[Y_PLANE].getRowStride(), colorPlanes[VU_PLANE].getRowStride(), roiRect); if (result) { dstY.rewind(); dstVU.rewind(); - byte[] data = new byte[dstY.capacity() + dstVU.capacity()]; - int[] strides = new int[] { colorPlanes[Y_PLANE].getRowStride(), - colorPlanes[VU_PLANE].getRowStride() }; - dstY.get(data, 0, dstY.capacity()); - dstVU.get(data, dstY.capacity(), dstVU.capacity()); - return new ClearsightImage(new YuvImage(data, ImageFormat.NV21, - mRefColorImage.getWidth(), mRefColorImage.getHeight(), - strides), roiRect); + return new ClearsightImage(dstY, dstVU, roiRect); } else { return null; } @@ -286,11 +299,13 @@ public class ClearSightNativeEngine { } public static class ClearsightImage { - private YuvImage mImage; + public final ByteBuffer mYplane; + public final ByteBuffer mVUplane; private Rect mRoiRect; - ClearsightImage(YuvImage image, int[] rect) { - mImage = image; + ClearsightImage(ByteBuffer yPlane, ByteBuffer vuPlane, int[] rect) { + mYplane = yPlane; + mVUplane = vuPlane; mRoiRect = new Rect(rect[0], rect[1], rect[0] + rect[2], rect[1] + rect[3]); } @@ -299,10 +314,6 @@ public class ClearSightNativeEngine { return mRoiRect; } - public long getDataLength() { - return (mImage==null?0:mImage.getYuvData().length); - } - public int getWidth() { return (mRoiRect.right - mRoiRect.left); } @@ -310,13 +321,6 @@ public class ClearSightNativeEngine { public int getHeight() { return (mRoiRect.bottom - mRoiRect.top); } - - public byte[] compressToJpeg() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - mImage.compressToJpeg(mRoiRect, 100, baos); - return baos.toByteArray(); - } } public static class CamSensorCalibrationData { |