/*
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;
}
}