/* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is collection of files collectively known as Open Camera. The Initial Developer of the Original Code is Almalence Inc. Portions created by Initial Developer are Copyright (C) 2013 by Almalence Inc. All Rights Reserved. */ package com.almalence.plugins.capture.preshot; import java.util.Date; import android.annotation.TargetApi; import android.content.SharedPreferences; import android.hardware.camera2.CaptureResult; import android.os.Build; import android.os.CountDownTimer; import android.preference.PreferenceManager; import android.util.Log; import android.view.LayoutInflater; import android.view.ViewGroup.LayoutParams; import android.widget.CompoundButton; import android.widget.RelativeLayout; import android.widget.Toast; /* <!-- +++ import com.almalence.opencam_plus.cameracontroller.CameraController; import com.almalence.opencam_plus.CameraParameters; import com.almalence.opencam_plus.ApplicationScreen; import com.almalence.opencam_plus.PluginCapture; import com.almalence.opencam_plus.PluginManager; import com.almalence.opencam_plus.R; import com.almalence.opencam_plus.ApplicationInterface; +++ --> */ // <!-- -+- import com.almalence.opencam.CameraParameters; import com.almalence.opencam.ApplicationScreen; import com.almalence.opencam.PluginCapture; import com.almalence.opencam.PluginManager; import com.almalence.opencam.R; import com.almalence.opencam.ApplicationInterface; import com.almalence.opencam.cameracontroller.CameraController; //-+- --> import com.almalence.ui.Switch.Switch; /*** * Implements back in time capture plugin * * Starts capturing images immediately after start. Stops capturing when shutter * button pressed. ***/ public class PreshotCapturePlugin extends PluginCapture { // preferences private static String PreShotInterval; private static String FPS; private static boolean RefocusPreference; private static boolean AutostartPreference; private static String PauseBetweenShots; private int preferenceFocusMode; private static boolean isSlowMode = false; private static boolean isBuffering = false; private static int counter = 0; private static final int REFOCUS_INTERVAL = 3; private Switch modeSwitcher; private boolean captureStarted = false; private boolean camera2Preference; public PreshotCapturePlugin() { super("com.almalence.plugins.preshotcapture", R.xml.preferences_capture_preshot, R.xml.preferences_capture_preshot, 0, null); } @Override public void onStart() { getPrefs(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ApplicationScreen.getMainContext()); camera2Preference = prefs.getBoolean(ApplicationScreen.getMainContext().getResources().getString(R.string.Preference_UseCamera2Key), false); if(CameraController.isNexus6 && camera2Preference) { prefs.edit().putBoolean(ApplicationScreen.getMainContext().getResources().getString(R.string.Preference_UseCamera2Key), false).commit(); CameraController.setUseCamera2(false); CameraController.isOldCameraOneModeLaunched = true; PluginManager.getInstance().setSwitchModeType(true); } } @Override public void onResume() { preferenceFocusMode = ApplicationScreen.instance.getFocusModePref(CameraParameters.AF_MODE_AUTO); ApplicationScreen.instance.muteShutter(false); captureStarted = false; } @Override public void onPause() { StopBuffering(); inCapture = false; SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ApplicationScreen.getMainContext()); ApplicationScreen.instance.setFocusModePref(preferenceFocusMode); prefs.edit().putBoolean(ApplicationScreen.getMainContext().getResources().getString(R.string.Preference_UseCamera2Key), camera2Preference).commit(); } @Override public void onStop() { ApplicationScreen.getGUIManager().removeViews(modeSwitcher, R.id.specialPluginsLayout3); if(CameraController.isNexus6 && camera2Preference) { CameraController.useCamera2OnRelaunch(true); CameraController.setUseCamera2(camera2Preference); } } @Override public void onDestroy() { PreShot.FreeBuffer(); } @Override public void onGUICreate() { getPrefs(); LayoutInflater inflator = ApplicationScreen.instance.getLayoutInflater(); modeSwitcher = (Switch) inflator.inflate(R.layout.plugin_capture_preshot_modeswitcher, null, false); modeSwitcher.setTextOn("Hi-Res"); modeSwitcher.setTextOff("Hi-Speed"); modeSwitcher.setChecked(isSlowMode); modeSwitcher.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ApplicationScreen.getMainContext()); SharedPreferences.Editor editor = prefs.edit(); editor.putString("modePrefPreShot", isChecked ? "1" : "0"); editor.commit(); getPrefs(); } }); ApplicationScreen.getGUIManager().removeViews(modeSwitcher, R.id.specialPluginsLayout3); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); params.addRule(RelativeLayout.ALIGN_PARENT_TOP); params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); ((RelativeLayout) ApplicationScreen.instance.findViewById(R.id.specialPluginsLayout3)).addView(this.modeSwitcher, params); this.modeSwitcher.setLayoutParams(params); } @Override public boolean needPreviewFrame() { return true; } private void getPrefs() { // Get the xml/preferences.xml preferences SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ApplicationScreen.getMainContext()); RefocusPreference = prefs.getBoolean("refocusPrefPreShot", false); AutostartPreference = prefs.getBoolean("autostartPrefPreShot", false); PauseBetweenShots = prefs.getString("pauseBetweenShotsPrefPreShot", "500"); PreShotInterval = prefs.getString("backInTimePrefPreShot", "5"); if (1 == Integer.parseInt(prefs.getString("modePrefPreShot", "0"))) { isSlowMode = true; FPS = "2"; } else { FPS = prefs.getString("fpsPrefPreShot", "4"); isSlowMode = false; } } @Override public void onCameraSetup() { if (AutostartPreference) if (PluginManager.getInstance().getProcessingCounter() == 0) StartBuffering(); } @Override public void setupCameraParameters() { if (!isSlowMode)// fast mode { try { if (CameraController.isModeAvailable(CameraController.getSupportedFocusModes(), CameraParameters.AF_MODE_CONTINUOUS_VIDEO)) { CameraController.setCameraFocusMode(CameraParameters.AF_MODE_CONTINUOUS_VIDEO); ApplicationScreen.instance.setFocusModePref(CameraParameters.AF_MODE_CONTINUOUS_VIDEO); } } catch (Exception e) { Log.i("Preshot capture", "Exception fast:" + e.getMessage()); } } else // slow mode { try { if (CameraController.isModeAvailable(CameraController.getSupportedFocusModes(), CameraParameters.AF_MODE_CONTINUOUS_PICTURE)) { CameraController.setCameraFocusMode(CameraParameters.AF_MODE_CONTINUOUS_PICTURE); ApplicationScreen.instance.setFocusModePref(CameraParameters.AF_MODE_CONTINUOUS_PICTURE); } } catch (Exception e) { Log.i("Preshot capture", "Exception slow:" + e.getMessage()); } } PluginManager.getInstance().sendMessage(ApplicationInterface.MSG_BROADCAST, ApplicationInterface.MSG_FOCUS_CHANGED); } @Override public void onExportFinished() { inCapture = false; if (modeSwitcher != null && isBuffering == false) modeSwitcher.setEnabled(true); if (AutostartPreference) StartBuffering(); } @Override public void onShutterClick() { if (captureStarted || AutostartPreference) { if (0 == PreShot.GetImageCount()) { Toast.makeText(ApplicationScreen.instance, "No images yet", Toast.LENGTH_SHORT).show(); return; } captureStarted = false; StopBuffering(); PluginManager.getInstance().sendMessage(ApplicationInterface.MSG_CAPTURE_FINISHED, String.valueOf(SessionID)); } else if (!inCapture) { if (!AutostartPreference && modeSwitcher != null) modeSwitcher.setEnabled(false); captureStarted = true; StartBuffering(); } } private static int frmCnt = 1; private static int preview_fps = 0; public static int imW = 0; public static int imH = 0; private long t1 = 0; private int cnt = 0; private double fpsInterval = 0; // starts buffering to native buffer void StartBuffering() { Date curDate = new Date(); SessionID = curDate.getTime(); ApplicationScreen.instance.muteShutter(true); resultCompleted = 0; isBuffering = true; if (!isSlowMode) { PreShot.FreeBuffer(); ApplicationScreen.getGUIManager().startContinuousCaptureIndication(); preview_fps = CameraController.getPreviewFrameRate(); if (CameraController.isHTCOne) preview_fps = 30; imW = ApplicationScreen.getPreviewWidth(); imH = ApplicationScreen.getPreviewHeight(); Log.i("Preshot capture", "StartBuffering trying to allocate!"); int secondsAllocated = PreShot.AllocateBuffer(imW, imH, Integer.parseInt(FPS), Integer.parseInt(PreShotInterval), 0); if (secondsAllocated == 0) { Log.i("Preshot capture", "StartBuffering failed, can't allocate native buffer!"); return; } PluginManager.getInstance().addToSharedMem("IsSlowMode" + SessionID, "false"); cnt = frmCnt % (preview_fps / Integer.parseInt(FPS))*10; fpsInterval = 1000.0/Integer.parseInt(FPS); t1 = System.currentTimeMillis(); inCapture = true; } else { // full size code PreShot.FreeBuffer(); CameraController.Size imageSize = CameraController.getCameraImageSize(); imW = imageSize.getWidth(); imH = imageSize.getHeight(); int secondsAllocated = PreShot.AllocateBuffer(imW, imH, Integer.parseInt(FPS), Integer.parseInt(PreShotInterval), 1); if (secondsAllocated == 0) { Log.i("Preshot capture", "StartBuffering failed, can't allocate native buffer!"); return; } PluginManager.getInstance().addToSharedMem("cameraMirrored" + SessionID, String.valueOf(CameraController.isFrontCamera())); PluginManager.getInstance().addToSharedMem("IsSlowMode" + SessionID, "true"); StartCaptureSequence(); } } void StopBuffering() { ApplicationScreen.getGUIManager().stopCaptureIndication(); ApplicationScreen.instance.muteShutter(false); if (modeSwitcher != null) modeSwitcher.setEnabled(false); if (!isBuffering) return; else isBuffering = false; counter = 0; resultCompleted = 0; PluginManager.getInstance().addToSharedMem("amountofcapturedframes" + SessionID, String.valueOf(PreShot.GetImageCount())); if (!isSlowMode) { frmCnt = 1; } } @Override public void onPreviewFrame(byte[] data) { if (isSlowMode || !isBuffering) return; long t2 = System.currentTimeMillis(); long timelapse = t2-t1; if (0 == cnt || timelapse>fpsInterval) { t1 = System.currentTimeMillis(); System.gc(); if (frmCnt == 1) PluginManager.getInstance().addToSharedMemExifTagsFromCamera(SessionID); PreShot.InsertToBuffer(data, ApplicationScreen.getGUIManager().getImageDataOrientation()); } frmCnt++; } void StartCaptureSequence() { if (!inCapture) { inCapture = true; if(CameraController.isAutoFocusPerform()) aboutToTakePicture = true; else CaptureFrame(); } } public void NotEnoughMemory() { Log.i("Preshot capture", "NotEnoughMemory!"); } @Override public void addToSharedMemExifTags(byte[] frameData) { if (0 == PreShot.GetImageCount()) { if (frameData != null) PluginManager.getInstance().addToSharedMemExifTagsFromJPEG(frameData, SessionID, -1); else PluginManager.getInstance().addToSharedMemExifTagsFromCamera(SessionID); } } @Override public void onImageTaken(int frame, byte[] frameData, int frame_len, int format) { PreShot.InsertToBuffer(frameData, ApplicationScreen.getGUIManager().getImageDataOrientation()); try { CameraController.startCameraPreview(); if (isBuffering) { ProcessPauseBetweenShots(); } } catch (RuntimeException e) { Log.i("Preshot capture", "StartPreview fail"); StopBuffering(); } } void ProcessPauseBetweenShots() { int interval = Integer.parseInt(PauseBetweenShots); if (interval == 0) { afterPause(); return; } new CountDownTimer(interval, interval) { public void onFinish() { afterPause(); } @Override public void onTick(long millisUntilFinished) { } }.start(); } void afterPause() { if (isBuffering) { int focusMode = ApplicationScreen.instance.getFocusModePref(-1); if (RefocusPreference || (counter >= REFOCUS_INTERVAL) && !(focusMode == CameraParameters.AF_MODE_CONTINUOUS_PICTURE || focusMode == CameraParameters.AF_MODE_CONTINUOUS_VIDEO || focusMode == CameraParameters.AF_MODE_INFINITY || focusMode == CameraParameters.AF_MODE_FIXED || focusMode == CameraParameters.AF_MODE_EDOF) && !ApplicationScreen.instance.getAutoFocusLock()) { counter = 0; aboutToTakePicture = true; if (!CameraController.autoFocus()) { aboutToTakePicture = false; CaptureFrame(); } } else { CaptureFrame(); } } } public void CaptureFrame() { if (isBuffering) { if (CameraController.getFocusState() == CameraController.FOCUS_STATE_FOCUSING) return; createRequestIDList(1); CameraController.captureImagesWithParams(1, CameraController.JPEG, null, null, null, null, false, false, true); counter++; } } @TargetApi(21) @Override public void onCaptureCompleted(CaptureResult result) { int requestID = requestIDArray[0]; resultCompleted++; Log.e("PreShotCapturePlugin", "onCaptureCompleted. resultCompleted = " +resultCompleted); if (result.getSequenceId() == requestID) { PluginManager.getInstance().addToSharedMemExifTagsFromCaptureResult(result, SessionID, resultCompleted); } } @Override public void onAutoFocus(boolean paramBoolean) { // on motorola xt5 cm7 this function is called twice! // on motorola droid's onAutoFocus seem to be called at every // startPreview, // causing additional frame(s) taken after sequence is finished if (aboutToTakePicture && isSlowMode) { CaptureFrame(); } aboutToTakePicture = false; } @Override public boolean onBroadcast(int arg1, int arg2) { if (arg1 == ApplicationInterface.MSG_STOP_CAPTURE) { StopBuffering(); return true; } else if (arg1 == ApplicationInterface.MSG_START_CAPTURE) { if (PluginManager.getInstance().getProcessingCounter() == 0) StartBuffering(); return true; } return false; } }