/* SonyCameraPreview Copyright (c) 2017 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.android.deviceplugin.sonycamera.utils; import com.example.sony.cameraremote.SimpleRemoteApi; import com.example.sony.cameraremote.utils.SimpleLiveviewSlicer; import org.json.JSONArray; import org.json.JSONObject; import java.io.IOException; /** * SonyカメラからのプレビューデータをWebサーバ経由で配信するクラス. * @author NTT DOCOMO, INC. */ public class SonyCameraPreview extends Thread { /** * プレビュー再生フラグ. * <p> * プレビューを再生中はtrue、それ以外はfalse. * </p> */ private boolean mWhileFetching; /** * SonyCameraのリモートAPI. */ private SimpleRemoteApi mRemoteApi; /** * Server for MotionJPEG. */ private MixedReplaceMediaServer mServer; /** * プレビューイベント通知リスナー. */ private OnPreviewListener mOnPreviewListener; /** * タイムスライス.(ms) */ private int mTimeSlice = 100; /** * コンストラクタ. * @param remoteApi Sonyカメラ API にアクセスするクラス */ public SonyCameraPreview(final SimpleRemoteApi remoteApi) { mRemoteApi = remoteApi; } @Override public void run() { SimpleLiveviewSlicer slicer = null; try { // Prepare for connecting. JSONObject replyJson = mRemoteApi.startLiveview(); if (!SonyCameraUtil.isErrorReply(replyJson)) { JSONArray resultsObj = replyJson.getJSONArray("result"); String liveviewUrl = null; if (1 <= resultsObj.length()) { // Obtain liveview URL from the result. liveviewUrl = resultsObj.getString(0); } if (liveviewUrl != null) { // Create Slicer to open the stream and parse it. slicer = new SimpleLiveviewSlicer(); slicer.open(liveviewUrl); } } if (slicer == null) { mOnPreviewListener.onError(); return; } if (mServer == null) { mServer = new MixedReplaceMediaServer(); mServer.setServerEventListener(new MixedReplaceMediaServer.ServerEventListener() { @Override public void onStart() { } @Override public void onStop() { mWhileFetching = false; } @Override public void onError() { mWhileFetching = false; } }); mServer.setServerName("SonyCameraDevicePlugin Server"); mServer.setContentType("image/jpg"); mServer.setTimeSlice(mTimeSlice); String ip = mServer.start(); if (ip == null) { mOnPreviewListener.onError(); return; } } mOnPreviewListener.onPreviewServer(mServer.getUrl()); while (mWhileFetching) { final SimpleLiveviewSlicer.Payload payload = slicer.nextPayload(); if (payload == null) { // never occurs continue; } mServer.offerMedia(payload.getJpegData()); } } catch (Exception e) { mOnPreviewListener.onError(); } finally { if (slicer != null) { try { slicer.close(); } catch (IOException e) { // do nothing } } try { mRemoteApi.stopLiveview(); } catch (IOException e) { // do nothing } if (mServer != null) { mServer.stop(); mServer = null; } mWhileFetching = false; mOnPreviewListener.onComplete(); } } /** * プレビューを開始します. */ public void startPreview() { mWhileFetching = true; start(); } /** * プレビューを停止します. */ public void stopPreview() { mWhileFetching = false; } /** * プレビュー撮影中か確認を行います. * @return 撮影中の場合はtrue、それ以外はfalse */ public boolean isPreview() { return mWhileFetching && mServer != null && mServer.isRunning(); } /** * プレビューを配信するサーバへのURLを返却します. * @return プレビューを配信するサーバへのURL */ public String getPreviewUrl() { if (mServer == null) { return null; } return mServer.getUrl(); } /** * タイムスライスを設定します. * <p> * デフォルトでは、100msが設定してあります。 * </p> * @param timeSlice タイムスライス(ms) */ public void setTimeSlice(final int timeSlice) { mTimeSlice = timeSlice; } /** * プレビューのイベントを通知するためのリスナーを設定します. * @param onPreviewListener リスナー */ public void setOnPreviewListener(OnPreviewListener onPreviewListener) { mOnPreviewListener = onPreviewListener; } /** * プレビューの通知を行うリスナークラス. */ public interface OnPreviewListener { /** * プレビューを出力するサーバを通知します. * @param url プレビューサーバへのURL */ void onPreviewServer(String url); /** * プレビューサーバ起動に失敗したことを通知します. */ void onError(); /** * プレビューサーバが完了したことを通知します. */ void onComplete(); } }