OSDN Git Service

7bdd115383908a423c02b2f5bd8254b11133502d
[gokigen/PKRemote.git] / app / src / main / java / net / osdn / gokigen / pkremote / camera / vendor / panasonic / wrapper / playback / PanasonicPlaybackControl.java
1 package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.playback;
2
3 import android.graphics.Bitmap;
4 import android.util.Log;
5
6 import androidx.annotation.NonNull;
7
8 import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraContent;
9 import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraContentListCallback;
10 import net.osdn.gokigen.pkremote.camera.interfaces.playback.ICameraFileInfo;
11 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IContentInfoCallback;
12 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentCallback;
13 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadContentListCallback;
14 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IDownloadThumbnailImageCallback;
15 import net.osdn.gokigen.pkremote.camera.interfaces.playback.IPlaybackControl;
16 import net.osdn.gokigen.pkremote.camera.playback.ProgressEvent;
17 import net.osdn.gokigen.pkremote.camera.utils.SimpleHttpClient;
18 import net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.IPanasonicCamera;
19
20 import java.util.ArrayDeque;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Queue;
25
26 public class PanasonicPlaybackControl implements IPlaybackControl
27 {
28     private final String TAG = toString();
29     private static final int COMMAND_POLL_QUEUE_MS = 50;
30     private IPanasonicCamera panasonicCamera = null;
31     private int timeoutMs = 50000;
32     private boolean isStarted = false;
33     private StringBuffer getObjectLists = null;
34     private List<ICameraContent> contentList;
35     private Queue<DownloadScreennailRequest> commandQueue;
36
37
38     public PanasonicPlaybackControl()
39     {
40         contentList = new ArrayList<>();
41     }
42
43     public void setCamera(IPanasonicCamera panasonicCamera, int timeoutMs)
44     {
45         Log.v(TAG, "setCamera() " + panasonicCamera.getFriendlyName());
46         this.panasonicCamera = panasonicCamera;
47         this.timeoutMs = timeoutMs;
48         this.commandQueue = new ArrayDeque<>();
49         commandQueue.clear();
50     }
51
52     private void getContentList()
53     {
54         if (panasonicCamera == null)
55         {
56             // URLが特定できていないため、送信できないので先に進める
57             return;
58         }
59
60         // PLAYモードに切り替える
61         String requestUrl = this.panasonicCamera.getCmdUrl() + "cam.cgi?mode=camcmd&value=playmode";
62         String reqPlay = SimpleHttpClient.httpGet(requestUrl, this.timeoutMs);
63         if (!reqPlay.contains("ok"))
64         {
65             Log.v(TAG, "CAMERA REPLIED ERROR : CHANGE PLAYMODE.");
66         }
67
68         ////////////  ある程度の数に区切って送られてくる... 何度か繰り返す必要があるようだ  ////////////
69         getObjectLists = new StringBuffer();
70         int sequenceNumber = 0;
71         int totalCount = 100000;
72         int returnedCount = 0;
73         while (totalCount > returnedCount)
74         {
75             Log.v(TAG, "  ===== getContentList() " + sequenceNumber + " =====");
76             sequenceNumber++;
77             String url = panasonicCamera.getObjUrl() + "Server0/CDS_control";
78             String postData = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>" +
79                     "<u:Browse xmlns:u=\"urn:schemas-upnp-org:service:ContentDirectory:" + sequenceNumber + "\" xmlns:pana=\"urn:schemas-panasonic-com:pana\">" +
80                     "<ObjectID>0</ObjectID><BrowseFlag>BrowseDirectChildren</BrowseFlag><Filter>*</Filter><StartingIndex>" + returnedCount + "</StartingIndex><RequestedCount>3500</RequestedCount><SortCriteria></SortCriteria>" +
81                     "<pana:X_FromCP>LumixLink2.0</pana:X_FromCP></u:Browse></s:Body></s:Envelope>";
82
83             String reply = SimpleHttpClient.httpPostWithHeader(url, postData, "SOAPACTION", "urn:schemas-upnp-org:service:ContentDirectory:" + sequenceNumber + "#Browse", "text/xml; charset=\"utf-8\"", timeoutMs);
84             if (reply.length() < 10) {
85                 Log.v(TAG, postData);
86                 Log.v(TAG, "ContentDirectory is FAILURE. [" + sequenceNumber + "]");
87                 break;
88             }
89             getObjectLists = getObjectLists.append(reply);
90             String matches = reply.substring(reply.indexOf("<TotalMatches>") + 14, reply.indexOf("</TotalMatches>"));
91             try
92             {
93                 totalCount = Integer.parseInt(matches);
94             }
95             catch (Exception e)
96             {
97                 e.printStackTrace();
98                 totalCount = 0;
99             }
100
101             String returned = reply.substring(reply.indexOf("<NumberReturned>") + 16, reply.indexOf("</NumberReturned>"));
102             try
103             {
104                 returnedCount = returnedCount + Integer.parseInt(returned);
105             }
106             catch (Exception e)
107             {
108                 e.printStackTrace();
109             }
110             Log.v(TAG, "  REPLY DATA : (" + matches + "/" + totalCount + ") [" + returned + "/" + returnedCount + "] " + " " + reply.length() + "bytes");
111         }
112     }
113
114     public void preprocessPlaymode()
115     {
116         // PLAYBACKモードに切り替わった直後に実行する処理をここに書く。
117         Log.v(TAG, "  preprocessPlaymode() : " + panasonicCamera.getObjUrl());
118
119         // 画像情報を取得
120         getContentList();
121
122         // スクリーンネイルを1こづつ取得するように変更
123         getScreenNailService();
124     }
125
126     @Override
127     public String getRawFileSuffix()
128     {
129         Log.v(TAG, " getRawFileSuffix()");
130         return ("RW2");
131     }
132
133     @Override
134     public void downloadContentList(IDownloadContentListCallback callback)
135     {
136         Log.v(TAG, " downloadContentList()");
137
138     }
139
140     @Override
141     public void getContentInfo(String path, String name, IContentInfoCallback callback)
142     {
143         Log.v(TAG, " getContentInfo() : " + path + " / " + name);
144         // 画像の情報を取得する
145
146     }
147
148     @Override
149     public void updateCameraFileInfo(@NonNull ICameraFileInfo info)
150     {
151         Log.v(TAG, " updateCameraFileInfo() : " + info.getFilename());
152
153
154     }
155
156     @Override
157     public void downloadContentScreennail(String path, IDownloadThumbnailImageCallback callback)
158     {
159         commandQueue.add(new DownloadScreennailRequest(path, callback));
160     }
161
162     /**
163      *   スクリーンネイルを取得するロジック
164      *
165      */
166     private void getScreenNailService()
167     {
168         if (isStarted)
169         {
170             // すでにスタートしている場合は、スレッドを走らせない
171             return;
172         }
173         Thread thread = new Thread(new Runnable() {
174             @Override
175             public void run() {
176                 while (true)
177                 {
178                     try
179                     {
180                         DownloadScreennailRequest request = commandQueue.poll();
181                         if (request != null)
182                         {
183                             downloadContentScreennailImpl(request.getPath(), request.getCallback());
184                         }
185                         Thread.sleep(COMMAND_POLL_QUEUE_MS);
186                     }
187                     catch (Exception e)
188                     {
189                         e.printStackTrace();
190                     }
191                 }
192             }
193         });
194         try
195         {
196             isStarted = true;
197             thread.start();
198         }
199         catch (Exception e)
200         {
201             e.printStackTrace();
202         }
203     }
204
205     private void downloadContentScreennailImpl(String path, IDownloadThumbnailImageCallback callback)
206     {
207         if (path.startsWith("/"))
208         {
209             path = path.substring(1);
210         }
211         String requestUrl =  panasonicCamera.getPictureUrl() + "DL" + path.substring(2, path.lastIndexOf(".")) + ".JPG";
212         Log.v(TAG, " downloadContentScreennail() : " + requestUrl + "  ");
213         try
214         {
215             Bitmap bmp = SimpleHttpClient.httpGetBitmap(requestUrl, timeoutMs);
216             HashMap<String, Object> map = new HashMap<>();
217             map.put("Orientation", 0);
218             callback.onCompleted(bmp, map);
219         }
220         catch (Throwable e)
221         {
222             e.printStackTrace();
223             callback.onErrorOccurred(new NullPointerException());
224         }
225     }
226
227     @Override
228     public void downloadContentThumbnail(String path, IDownloadThumbnailImageCallback callback)
229     {
230         if (path.startsWith("/"))
231         {
232             path = path.substring(1);
233         }
234         String requestUrl =  panasonicCamera.getPictureUrl() + "DT" + path.substring(2, path.lastIndexOf(".")) + ".JPG";
235         Log.v(TAG, " downloadContentThumbnail() : " + path + "  [" +  requestUrl + "]");
236         try
237         {
238             Bitmap bmp = SimpleHttpClient.httpGetBitmap(requestUrl, timeoutMs);
239             HashMap<String, Object> map = new HashMap<>();
240             map.put("Orientation", 0);
241             callback.onCompleted(bmp, map);
242         }
243         catch (Throwable e)
244         {
245             e.printStackTrace();
246             callback.onErrorOccurred(new NullPointerException());
247         }
248     }
249
250     @Override
251     public void downloadContent(String path, boolean isSmallSize, final IDownloadContentCallback callback)
252     {
253         if (path.startsWith("/"))
254         {
255             path = path.substring(1);
256         }
257         String url =  panasonicCamera.getPictureUrl() + path;
258         if (isSmallSize)
259         {
260             url =  panasonicCamera.getPictureUrl() + "DL" + path.substring(2, path.lastIndexOf(".")) + ".JPG";
261         }
262         Log.v(TAG, "downloadContent()  PATH : " + path + " GET URL : " + url + "  [" + isSmallSize + "]");
263
264         try
265         {
266             SimpleHttpClient.httpGetBytes(url, timeoutMs, new SimpleHttpClient.IReceivedMessageCallback() {
267                 @Override
268                 public void onCompleted() {
269                     callback.onCompleted();
270                 }
271
272                 @Override
273                 public void onErrorOccurred(Exception e) {
274                     callback.onErrorOccurred(e);
275                 }
276
277                 @Override
278                 public void onReceive(int readBytes, int length, int size, byte[] data) {
279                     float percent = (length == 0) ? 0.0f : ((float) readBytes / (float) length);
280                     //Log.v(TAG, " onReceive : " + readBytes + " " + length + " " + size);
281                     ProgressEvent event = new ProgressEvent(percent, null);
282                     callback.onProgress(data, size, event);
283                 }
284             });
285         }
286         catch (Throwable e)
287         {
288             e.printStackTrace();
289         }
290     }
291
292     @Override
293     public void getCameraContentList(ICameraContentListCallback callback)
294     {
295         Log.v(TAG, "  getCameraContentList()");
296
297         // 画像情報を取得
298         getContentList();
299
300         contentList.clear();
301         try
302         {
303             if (getObjectLists == null)
304             {
305                 //何もしないで終了する
306                 return;
307             }
308             String objectString = getObjectLists.toString();
309             String checkUrl = panasonicCamera.getPictureUrl();
310             int maxIndex = objectString.length() - checkUrl.length();
311             int index = 0;
312
313             // データを解析してリストを作る
314             while ((index >= 0) && (index < maxIndex))
315             {
316                 index = objectString.indexOf(checkUrl, index);
317                 if (index > 0)
318                 {
319                     int lastIndex = objectString.indexOf("&", index);
320                     String picUrl = objectString.substring(index + checkUrl.length(), lastIndex);
321                     if (picUrl.startsWith("DO"))
322                     {
323                         // DO(オリジナル), DL(スクリーンネイル?), DT(サムネイル?)
324                         //Log.v(TAG, " pic : " + picUrl);
325                         PanasonicImageContentInfo contentInfo = new PanasonicImageContentInfo(picUrl);
326                         contentList.add(contentInfo);
327                     }
328                     index = lastIndex;
329                 }
330             }
331             if (callback != null)
332             {
333                 callback.onCompleted(contentList);
334             }
335         }
336         catch (Exception e)
337         {
338             e.printStackTrace();
339             if (callback != null)
340             {
341                 callback.onErrorOccurred(e);
342             }
343         }
344     }
345
346     /**
347      *   スクリーンネイルの取得キューで使用するクラス
348      */
349     private class DownloadScreennailRequest
350     {
351         private final String path;
352         private final IDownloadThumbnailImageCallback callback;
353         DownloadScreennailRequest(String path, IDownloadThumbnailImageCallback callback)
354         {
355             this.path = path;
356             this.callback = callback;
357         }
358
359         String getPath()
360         {
361             return (path);
362         }
363         IDownloadThumbnailImageCallback getCallback()
364         {
365             return (callback);
366         }
367     }
368 }