1 package net.osdn.gokigen.pkremote.camera.vendor.panasonic.wrapper.playback;
3 import android.graphics.Bitmap;
4 import android.util.Log;
6 import androidx.annotation.NonNull;
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;
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;
26 public class PanasonicPlaybackControl implements IPlaybackControl
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;
38 public PanasonicPlaybackControl()
40 contentList = new ArrayList<>();
43 public void setCamera(IPanasonicCamera panasonicCamera, int timeoutMs)
45 Log.v(TAG, "setCamera() " + panasonicCamera.getFriendlyName());
46 this.panasonicCamera = panasonicCamera;
47 this.timeoutMs = timeoutMs;
48 this.commandQueue = new ArrayDeque<>();
52 private void getContentList()
54 if (panasonicCamera == null)
56 // URLが特定できていないため、送信できないので先に進める
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"))
65 Log.v(TAG, "CAMERA REPLIED ERROR : CHANGE PLAYMODE.");
68 //////////// ある程度の数に区切って送られてくる... 何度か繰り返す必要があるようだ ////////////
69 getObjectLists = new StringBuffer();
70 int sequenceNumber = 0;
71 int totalCount = 100000;
72 int returnedCount = 0;
73 while (totalCount > returnedCount)
75 Log.v(TAG, " ===== getContentList() " + 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>";
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) {
86 Log.v(TAG, "ContentDirectory is FAILURE. [" + sequenceNumber + "]");
89 getObjectLists = getObjectLists.append(reply);
90 String matches = reply.substring(reply.indexOf("<TotalMatches>") + 14, reply.indexOf("</TotalMatches>"));
93 totalCount = Integer.parseInt(matches);
101 String returned = reply.substring(reply.indexOf("<NumberReturned>") + 16, reply.indexOf("</NumberReturned>"));
104 returnedCount = returnedCount + Integer.parseInt(returned);
110 Log.v(TAG, " REPLY DATA : (" + matches + "/" + totalCount + ") [" + returned + "/" + returnedCount + "] " + " " + reply.length() + "bytes");
114 public void preprocessPlaymode()
116 // PLAYBACKモードに切り替わった直後に実行する処理をここに書く。
117 Log.v(TAG, " preprocessPlaymode() : " + panasonicCamera.getObjUrl());
122 // スクリーンネイルを1こづつ取得するように変更
123 getScreenNailService();
127 public String getRawFileSuffix()
129 Log.v(TAG, " getRawFileSuffix()");
134 public void downloadContentList(IDownloadContentListCallback callback)
136 Log.v(TAG, " downloadContentList()");
141 public void getContentInfo(String path, String name, IContentInfoCallback callback)
143 Log.v(TAG, " getContentInfo() : " + path + " / " + name);
149 public void updateCameraFileInfo(@NonNull ICameraFileInfo info)
151 Log.v(TAG, " updateCameraFileInfo() : " + info.getFilename());
157 public void downloadContentScreennail(String path, IDownloadThumbnailImageCallback callback)
159 commandQueue.add(new DownloadScreennailRequest(path, callback));
166 private void getScreenNailService()
170 // すでにスタートしている場合は、スレッドを走らせない
173 Thread thread = new Thread(new Runnable() {
180 DownloadScreennailRequest request = commandQueue.poll();
183 downloadContentScreennailImpl(request.getPath(), request.getCallback());
185 Thread.sleep(COMMAND_POLL_QUEUE_MS);
205 private void downloadContentScreennailImpl(String path, IDownloadThumbnailImageCallback callback)
207 if (path.startsWith("/"))
209 path = path.substring(1);
211 String requestUrl = panasonicCamera.getPictureUrl() + "DL" + path.substring(2, path.lastIndexOf(".")) + ".JPG";
212 Log.v(TAG, " downloadContentScreennail() : " + requestUrl + " ");
215 Bitmap bmp = SimpleHttpClient.httpGetBitmap(requestUrl, timeoutMs);
216 HashMap<String, Object> map = new HashMap<>();
217 map.put("Orientation", 0);
218 callback.onCompleted(bmp, map);
223 callback.onErrorOccurred(new NullPointerException());
228 public void downloadContentThumbnail(String path, IDownloadThumbnailImageCallback callback)
230 if (path.startsWith("/"))
232 path = path.substring(1);
234 String requestUrl = panasonicCamera.getPictureUrl() + "DT" + path.substring(2, path.lastIndexOf(".")) + ".JPG";
235 Log.v(TAG, " downloadContentThumbnail() : " + path + " [" + requestUrl + "]");
238 Bitmap bmp = SimpleHttpClient.httpGetBitmap(requestUrl, timeoutMs);
239 HashMap<String, Object> map = new HashMap<>();
240 map.put("Orientation", 0);
241 callback.onCompleted(bmp, map);
246 callback.onErrorOccurred(new NullPointerException());
251 public void downloadContent(String path, boolean isSmallSize, final IDownloadContentCallback callback)
253 if (path.startsWith("/"))
255 path = path.substring(1);
257 String url = panasonicCamera.getPictureUrl() + path;
260 url = panasonicCamera.getPictureUrl() + "DL" + path.substring(2, path.lastIndexOf(".")) + ".JPG";
262 Log.v(TAG, "downloadContent() PATH : " + path + " GET URL : " + url + " [" + isSmallSize + "]");
266 SimpleHttpClient.httpGetBytes(url, timeoutMs, new SimpleHttpClient.IReceivedMessageCallback() {
268 public void onCompleted() {
269 callback.onCompleted();
273 public void onErrorOccurred(Exception e) {
274 callback.onErrorOccurred(e);
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);
293 public void getCameraContentList(ICameraContentListCallback callback)
295 Log.v(TAG, " getCameraContentList()");
303 if (getObjectLists == null)
308 String objectString = getObjectLists.toString();
309 String checkUrl = panasonicCamera.getPictureUrl();
310 int maxIndex = objectString.length() - checkUrl.length();
314 while ((index >= 0) && (index < maxIndex))
316 index = objectString.indexOf(checkUrl, index);
319 int lastIndex = objectString.indexOf("&", index);
320 String picUrl = objectString.substring(index + checkUrl.length(), lastIndex);
321 if (picUrl.startsWith("DO"))
323 // DO(オリジナル), DL(スクリーンネイル?), DT(サムネイル?)
324 //Log.v(TAG, " pic : " + picUrl);
325 PanasonicImageContentInfo contentInfo = new PanasonicImageContentInfo(picUrl);
326 contentList.add(contentInfo);
331 if (callback != null)
333 callback.onCompleted(contentList);
339 if (callback != null)
341 callback.onErrorOccurred(e);
347 * スクリーンネイルの取得キューで使用するクラス
349 private class DownloadScreennailRequest
351 private final String path;
352 private final IDownloadThumbnailImageCallback callback;
353 DownloadScreennailRequest(String path, IDownloadThumbnailImageCallback callback)
356 this.callback = callback;
363 IDownloadThumbnailImageCallback getCallback()