OSDN Git Service

インターバル撮影機能を入れる。
[gokigen/A01c.git] / wear / src / main / java / jp / sfjp / gokigen / a01c / olycamerawrapper / takepicture / BracketingShotControl.java
1 package jp.sfjp.gokigen.a01c.olycamerawrapper.takepicture;
2
3 import android.graphics.Color;
4 import android.graphics.PointF;
5 import android.util.Log;
6
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.concurrent.ExecutorService;
10 import java.util.concurrent.Executors;
11
12 import jp.co.olympus.camerakit.OLYCamera;
13 import jp.co.olympus.camerakit.OLYCameraAutoFocusResult;
14 import jp.sfjp.gokigen.a01c.IShowInformation;
15 import jp.sfjp.gokigen.a01c.liveview.IAutoFocusFrameDisplay;
16 import jp.sfjp.gokigen.a01c.olycamerawrapper.IIndicatorControl;
17 import jp.sfjp.gokigen.a01c.olycamerawrapper.property.IOlyCameraProperty;
18
19 /**
20  *   インターバル撮影&ブラケッティング撮影 実行クラス
21  *
22  *
23  * Created by MRSa on 2017/07/19.
24  */
25 public class BracketingShotControl implements OLYCamera.TakePictureCallback
26 {
27     private final String TAG = toString();
28
29     private static final int BRACKETING_INTERVAL_MILLISECOND = 300; // 撮影待ち時間(ms)
30     private static final int BRACKETING_PROPERTY_VALUE_SET_RETRY = 10;
31
32     private final OLYCamera camera;
33     private final IAutoFocusFrameDisplay autoFocusFrame;
34     private final IShowInformation statusDrawer;
35     private final IIndicatorControl indicator;
36     private boolean isShootingWait = false;
37     private boolean isBracketingAction = false;
38     private int retryUpdateBracketingStatus = 0;
39     private int waitSeconds = 0;  // 撮影待ち時間
40
41     private int bracketCount = 0;
42     private String targetPropertyName = null;
43     private String originalProperty = null;
44     private int  originalPropertyIndex = -1;
45     private List<String> propertyValueList = null;
46
47     /**
48      *  コンストラクタ
49      *
50      */
51     public BracketingShotControl(OLYCamera camera, IAutoFocusFrameDisplay focusFrameDrawer, IIndicatorControl indicator, IShowInformation statusDrawer)
52     {
53         this.camera = camera;
54         this.autoFocusFrame = focusFrameDrawer;
55         this.indicator = indicator;
56         this.statusDrawer = statusDrawer;
57     }
58
59     /**
60      *  ブラケッティング対象のプロパティの現在設定値と、その選択肢を記憶する
61      *
62      * @param name ブラケッティング対象の名前
63      * @return  ブラケッティングの現在設定値
64      */
65     private int prepareBracketProperty(String name)
66     {
67         try
68         {
69             targetPropertyName = name;
70             if (name.length() > 0)
71             {
72                 originalProperty = camera.getCameraPropertyValue(name);
73                 propertyValueList = camera.getCameraPropertyValueList(name);
74                 if (bracketCount < 0)
75                 {
76                     bracketCount = propertyValueList.size();
77                 }
78                 return (propertyValueList.indexOf(originalProperty));
79             }
80             else
81             {
82                 originalProperty = null;
83                 propertyValueList = null;
84             }
85         }
86         catch (Exception e)
87         {
88             originalProperty = null;
89             propertyValueList = null;
90             e.printStackTrace();
91             System.gc();
92         }
93         return (-1);
94     }
95
96
97     /**
98      *   ブラケッティング対象のプロパティを特定する
99      *
100      * @param isBracketing プロパティ
101      * @return true : 対象の特定完了 / false : 対象の特定失敗
102      */
103     private boolean decideBracketProperty(int isBracketing)
104     {
105         switch (isBracketing)
106         {
107             case IBracketingShotStyle.BRACKET_EXPREV:
108                 // 露出ブラケット
109                 targetPropertyName = IOlyCameraProperty.EXPOSURE_COMPENSATION;
110                 break;
111
112             case IBracketingShotStyle.BRACKET_APERTURE:
113                 // 絞り値設定
114                 targetPropertyName = IOlyCameraProperty.APERTURE;
115                 break;
116
117             case IBracketingShotStyle.BRACKET_ISO:
118                 // ISO
119                 targetPropertyName = IOlyCameraProperty.ISO_SENSITIVITY;
120                 break;
121
122             case IBracketingShotStyle.BRACKET_SHUTTER:
123                 // シャッターブラケット
124                 targetPropertyName = IOlyCameraProperty.SHUTTER_SPEED;
125                 break;
126
127             case IBracketingShotStyle.BRACKET_WB:
128                 // ホワイトバランスブラケット
129                 targetPropertyName = IOlyCameraProperty.WB_MODE;
130                 bracketCount = -1;
131                 break;
132
133             case IBracketingShotStyle.BRACKET_COLOR_TONE:
134                 // ピクチャーモードブラケット
135                 targetPropertyName = IOlyCameraProperty.COLOR_TONE;
136                 bracketCount = -1;
137                 break;
138
139             case IBracketingShotStyle.BRACKET_NONE:
140                 // パラメータは変更しないパターン...
141                 targetPropertyName = "";
142                 break;
143
144             default:
145                 // 何もしない
146                 return (false);
147         }
148         originalPropertyIndex = prepareBracketProperty(targetPropertyName);
149         return (true);
150     }
151
152
153     /**
154      *  写真撮影(ブラケッティング撮影)を開始する
155      *    bracketingStyle : ブラケッティングスタイル
156      *    bracketingCount : 撮影枚数
157      *    durationSeconds : 撮影間隔(単位:秒)
158      */
159     public void bracketingShot(int bracketingStyle, int bracketingCount, int durationSeconds)
160     {
161         if ((camera.isTakingPicture())||(camera.isRecordingVideo())||(isBracketingAction))
162         {
163             // スチル or ムービー撮影中、ブラケッティング撮影中なら、何もしない
164             return;
165         }
166
167         // ブラケッティング撮影の準備
168         bracketCount = bracketingCount;
169         if (!decideBracketProperty(bracketingStyle))
170         {
171             // ブラケッティング指定ではないので、何もせずに終了する
172             return;
173         }
174
175         // 撮影間隔 (単位:秒)
176         waitSeconds = durationSeconds;
177
178         // ブラケッティング撮影開始! (別スレッドでブラケッティング撮影を開始する)
179         ExecutorService executor = Executors.newSingleThreadExecutor();
180         executor.submit(new Runnable()
181         {
182             @Override
183             public void run()
184             {
185                 isBracketingAction = true;
186                 updateMessage("INT");
187                 try
188                 {
189                     startBracket();
190                 }
191                 catch (Exception e)
192                 {
193                     e.printStackTrace();
194                 }
195                 isBracketingAction = false;
196                 updateMessage("");
197             }
198         });
199     }
200
201     /**
202      *   画面にメッセージを表示する
203      *
204      * @param msg  表示するメッセージ
205      */
206     private void updateMessage(String msg)
207     {
208         statusDrawer.setMessage(IShowInformation.AREA_C, Color.CYAN, msg);
209     }
210
211     /**
212      *   ブラケッティング撮影を開始する
213      *   (これは別スレッドで処理する)
214      *
215      *      一番小さい選択肢(インデックス)から設定された撮影枚数分、
216      *      徐々に選択肢をずらして撮影する。
217      *
218      */
219     private void startBracket()
220     {
221         int startIndex = originalPropertyIndex - (bracketCount / 2);
222         if (propertyValueList != null)
223         {
224             if ((startIndex + bracketCount) > propertyValueList.size())
225             {
226                 startIndex = propertyValueList.size() - bracketCount;
227             }
228         }
229         if (startIndex < 0)
230         {
231             startIndex = 0;
232         }
233
234         PointF afPoint = camera.getActualAutoFocusPoint();
235         for (int index = 0; index < bracketCount; index++)
236         {
237             // 撮影条件を更新する
238             updateBracketingStatus(index, startIndex);
239             startIndex++;
240
241             try
242             {
243                 // AFポイントを設定する
244                 if (afPoint != null)
245                 {
246                     camera.setAutoFocusPoint(afPoint);
247                 }
248             }
249             catch (Exception e)
250             {
251                 e.printStackTrace();
252             }
253
254             if (bracketCount == 1)
255             {
256                 // 1枚しか撮影しない時は、撮影前にウェイトをかける
257                 waitSeconds(waitSeconds);
258             }
259
260             try
261             {
262                 // 写真を撮影する
263                 camera.takePicture(new HashMap<String, Object>(), this);
264                 isShootingWait = true;
265                 while (isShootingWait)
266                 {
267                     // ここで撮影状態が整うまで少し待つ
268                     Thread.sleep(BRACKETING_INTERVAL_MILLISECOND);
269                     updateShootingWaitStatus();
270                 }
271             }
272             catch (Exception e)
273             {
274                 e.printStackTrace();
275             }
276
277             // 撮影したことをバイブレータで知らせる
278             statusDrawer.vibrate(IShowInformation.VIBRATE_PATTERN_SIMPLE_SHORT);
279
280             // 指定された時間待機、ただし、最後の撮影が終わったあとには待たないようにする。
281             if ((index + 1) < bracketCount)
282             {
283                 waitSeconds(waitSeconds);
284             }
285         }
286         try
287         {
288             // 変更したプロパティ値を元の値に戻す...ちょっと待ってから
289             Thread.sleep(BRACKETING_INTERVAL_MILLISECOND);
290             if (originalProperty != null)
291             {
292                 camera.setCameraPropertyValue(targetPropertyName, originalProperty);
293             }
294
295             // とにかくAF枠を消す。
296             camera.clearAutoFocusPoint();
297             autoFocusFrame.hideFocusFrame();
298
299             indicator.onAfLockUpdate(false);
300
301             // 撮影終了をバイブレータで知らせる
302             statusDrawer.vibrate(IShowInformation.VIBRATE_PATTERN_SIMPLE_MIDDLE);
303         }
304         catch (Exception e)
305         {
306             e.printStackTrace();
307         }
308     }
309
310     /**
311      *   指定された時間待機する
312      *
313      * @param seconds  待機秒数
314      */
315     private void waitSeconds(int seconds)
316     {
317         for (int count = seconds; count > 0; count--)
318         {
319             // 待ち時間(単位:秒)
320             try
321             {
322                 // BKT表示(撮影枚数表示と待ち時間)を変える
323                 updateMessage("WAIT " + count + "s.");
324                 Thread.sleep(1000);
325             }
326             catch (Exception e)
327             {
328                 e.printStackTrace();
329             }
330         }
331         updateMessage("");
332     }
333
334     /**
335      *   ブラケッティング撮影の状態を更新する
336      *
337      * @param index  撮影が終了したカウント(0始まり)
338      */
339     private void updateBracketingStatus(int index, int currentIndex)
340     {
341         Log.v(TAG, "updateBracketingStatus() : " + index + "(" + currentIndex + ")");
342
343         // カメラのプロパティ設定を変える
344         try
345         {
346             if (propertyValueList != null)
347             {
348                 Thread.sleep(BRACKETING_INTERVAL_MILLISECOND);
349                 camera.setCameraPropertyValue(targetPropertyName, propertyValueList.get(currentIndex));
350             }
351         }
352         catch (Exception e)
353         {
354             e.printStackTrace();
355
356             // 頭に来たので、再度呼ぶ (リトライオーバーするまで)
357             if (retryUpdateBracketingStatus < BRACKETING_PROPERTY_VALUE_SET_RETRY)
358             {
359                 retryUpdateBracketingStatus++;
360                 updateBracketingStatus(index, currentIndex);
361             }
362         }
363         retryUpdateBracketingStatus = 0;
364
365         // 撮影枚数表示を変える
366         updateMessage("INT " + (index + 1) + "/" + bracketCount);
367     }
368
369     /**
370      *   カメラの状態を取得し、撮影可能か確認する。
371      *   (trueならまだ撮影処理中、falseなら撮影可能)
372      */
373     private void updateShootingWaitStatus()
374     {
375         boolean isBusy = false;
376         try
377         {
378             isBusy = ((camera.isTakingPicture())||(camera.isMediaBusy())||(camera.isRecordingVideo()));
379
380             // ちょっと待ち時間をとりたい...
381             String messageToShow = "getShootingBusyStatus() : " + String.valueOf(isBusy);
382             Log.v(TAG, messageToShow);
383         }
384         catch (Exception e)
385         {
386             e.printStackTrace();
387         }
388         isShootingWait = isBusy;
389     }
390
391     /**
392      *   OLYCamera.TakePictureCallback の実装
393      *
394      *
395      */
396     @Override
397     public void onProgress(OLYCamera olyCamera, OLYCamera.TakingProgress takingProgress, OLYCameraAutoFocusResult olyCameraAutoFocusResult)
398     {
399         // 特に何もしないでおこう
400     }
401
402     /**
403      *   OLYCamera.TakePictureCallback の実装
404      *
405      */
406     @Override
407     public void onCompleted()
408     {
409         // 撮影待ち状態の更新
410         updateShootingWaitStatus();
411     }
412
413     /**
414      *   OLYCamera.TakePictureCallback の実装
415      *
416      * @param e 例外情報
417      */
418     @Override
419     public void onErrorOccurred(Exception e)
420     {
421          e.printStackTrace();
422
423          // 撮影待ち状態の更新
424          updateShootingWaitStatus();
425     }
426 }