OSDN Git Service

21422656b5864abff4d6c9d547d637b4872c78dc
[gokigen/Gr2Control.git] / app / src / main / java / net / osdn / gokigen / gr2control / camera / utils / SimpleLiveviewSlicer.java
1 package net.osdn.gokigen.gr2control.camera.utils;
2
3 import android.util.Log;
4
5 import java.io.ByteArrayOutputStream;
6 import java.io.EOFException;
7 import java.io.InputStream;
8 import java.net.HttpURLConnection;
9 import java.net.URL;
10
11 public class SimpleLiveviewSlicer
12 {
13     private static final String TAG = SimpleLiveviewSlicer.class.getSimpleName();
14     public static final class Payload
15     {
16         // jpeg data container
17         final byte[] jpegData;
18
19         // padding data container
20         final byte[] paddingData;
21
22         /**
23          * Constructor
24          */
25         private Payload(byte[] jpeg, byte[] padding)
26         {
27             this.jpegData = jpeg;
28             this.paddingData = padding;
29         }
30         public byte[] getJpegData()
31         {
32             return (jpegData);
33         }
34     }
35
36     private static final int CONNECTION_TIMEOUT = 2000; // [msec]
37     private HttpURLConnection mHttpConn;
38     private InputStream mInputStream;
39
40     public void open(String liveviewUrl)
41     {
42         try
43         {
44             if ((mInputStream != null)||(mHttpConn != null))
45             {
46                 Log.v(TAG, "Slicer is already open.");
47                 return;
48             }
49
50             final URL urlObj = new URL(liveviewUrl);
51             mHttpConn = (HttpURLConnection) urlObj.openConnection();
52             mHttpConn.setRequestMethod("GET");
53             mHttpConn.setConnectTimeout(CONNECTION_TIMEOUT);
54             mHttpConn.connect();
55             if (mHttpConn.getResponseCode() == HttpURLConnection.HTTP_OK)
56             {
57                 mInputStream = mHttpConn.getInputStream();
58             }
59         }
60         catch (Exception e)
61         {
62             e.printStackTrace();
63         }
64     }
65
66     public void close()
67     {
68         try
69         {
70             if (mInputStream != null)
71             {
72                 mInputStream.close();
73                 mInputStream = null;
74             }
75         }
76         catch (Exception e)
77         {
78             e.printStackTrace();
79         }
80         try
81         {
82             if (mHttpConn != null)
83             {
84                 mHttpConn.disconnect();
85                 mHttpConn = null;
86             }
87         }
88         catch (Exception e)
89         {
90             e.printStackTrace();
91         }
92     }
93
94     public Payload nextPayload()
95     {
96         Payload payload = null;
97         try
98         {
99             while ((mInputStream != null)&&(payload == null))
100             {
101                 // Common Header
102                 int readLength = 1 + 1 + 2 + 4;
103                 byte[] commonHeader = readBytes(mInputStream, readLength);
104                 if ((commonHeader == null)||(commonHeader.length != readLength))
105                 {
106                     Log.v(TAG, "Cannot read stream for common header.");
107                     payload = null;
108                     break;
109                 }
110                 if (commonHeader[0] != (byte) 0xFF)
111                 {
112                     Log.v(TAG, "Unexpected data format. (Start byte)");
113                     payload = null;
114                     break;
115                 }
116                 switch (commonHeader[1])
117                 {
118                     case (byte) 0x12:
119                         // This is information header for streaming. skip this packet.
120                         readLength = 4 + 3 + 1 + 2 + 118 + 4 + 4 + 24;
121                         //commonHeader = null;
122                         readBytes(mInputStream, readLength);
123                         break;
124
125                     case (byte) 0x01:
126                     case (byte) 0x11:
127                         payload = readPayload();
128                         break;
129
130                     default:
131                         break;
132                 }
133             }
134         }
135         catch (Exception e)
136         {
137             e.printStackTrace();
138             System.gc();
139         }
140         return (payload);
141     }
142
143     private Payload readPayload()
144     {
145         try
146         {
147             if (mInputStream != null)
148             {
149                 // Payload Header
150                 int readLength = 4 + 3 + 1 + 4 + 1 + 115;
151                 byte[] payloadHeader = readBytes(mInputStream, readLength);
152                 if ((payloadHeader == null)||(payloadHeader.length != readLength))
153                 {
154                     throw new EOFException("Cannot read stream for payload header.");
155                 }
156                 if (payloadHeader[0] != (byte) 0x24 || payloadHeader[1] != (byte) 0x35
157                         || payloadHeader[2] != (byte) 0x68
158                         || payloadHeader[3] != (byte) 0x79)
159                 {
160                     throw new EOFException("Unexpected data format. (Start code)");
161                 }
162                 int jpegSize = bytesToInt(payloadHeader, 4, 3);
163                 int paddingSize = bytesToInt(payloadHeader, 7, 1);
164
165                 // Payload Data
166                 byte[] jpegData = readBytes(mInputStream, jpegSize);
167                 byte[] paddingData = readBytes(mInputStream, paddingSize);
168
169                 return (new Payload(jpegData, paddingData));
170             }
171         }
172         catch (EOFException eo)
173         {
174             eo.printStackTrace();
175             close();
176         }
177         catch (Exception e)
178         {
179             e.printStackTrace();
180         }
181         return (null);
182     }
183
184     private static int bytesToInt(byte[] byteData, int startIndex, int count)
185     {
186         int ret = 0;
187         try
188         {
189             for (int i = startIndex; i < startIndex + count; i++)
190             {
191                 ret = (ret << 8) | (byteData[i] & 0xff);
192             }
193         }
194         catch (Exception e)
195         {
196             e.printStackTrace();
197         }
198         return (ret);
199     }
200
201     private static byte[] readBytes(InputStream in, int length)
202     {
203         byte[] ret;
204         try
205         {
206             ByteArrayOutputStream tmpByteArray = new ByteArrayOutputStream();
207             byte[] buffer = new byte[1024];
208             while (true)
209             {
210                 int trialReadlen = Math.min(buffer.length, length - tmpByteArray.size());
211                 int readlen = in.read(buffer, 0, trialReadlen);
212                 if (readlen < 0)
213                 {
214                     break;
215                 }
216                 tmpByteArray.write(buffer, 0, readlen);
217                 if (length <= tmpByteArray.size())
218                 {
219                     break;
220                 }
221             }
222             ret = tmpByteArray.toByteArray();
223             tmpByteArray.close();
224         }
225         catch (Exception e)
226         {
227             e.printStackTrace();
228             ret = null;
229         }
230         return (ret);
231     }
232
233     /**
234      *   先頭のjpegマーカーが出てくるまで読み飛ばす
235      *
236      */
237     private void skipJpegMarkStart(InputStream stream)
238     {
239         int searchIndex = 0;
240         int[] startmarker = { 0x0d, 0x0a, 0x0d, 0x0a, 0xff, 0xd8 };
241         while (true)
242         {
243             try
244             {
245                 int data = stream.read();
246                 if (data == startmarker[searchIndex])
247                 {
248                     searchIndex++;
249                     if (searchIndex >= startmarker.length)
250                     {
251                         break;
252                     }
253                 }
254             }
255             catch (Exception e)
256             {
257                 e.printStackTrace();
258                 return;
259             }
260         }
261     }
262
263     /**
264      *
265      *
266      */
267     public Payload nextPayloadForMotionJpeg()
268     {
269         int searchIndex = 0;
270         int[] endmarker = { 0xff, 0xd9, 0x0d, 0x0a, 0x0d, 0x0a };
271         Payload payload = null;
272         try
273         {
274             while ((mInputStream != null)&&(payload == null))
275             {
276                 skipJpegMarkStart(mInputStream);
277                 ByteArrayOutputStream tmpByteArray = new ByteArrayOutputStream();
278                 // 先頭にJPEGのマークを詰める
279                 tmpByteArray.write(0xff);
280                 tmpByteArray.write(0xd8);
281                 while (true)
282                 {
283                     try
284                     {
285                         // 1byteづつの読み込み... 本当は複数バイト読み出しで処理したい
286                         int data = mInputStream.read();
287                         tmpByteArray.write(data);
288                         if (data == endmarker[searchIndex])
289                         {
290                             searchIndex++;
291                             if (searchIndex >= endmarker.length)
292                             {
293                                 break;
294                             }
295                         }
296                         else
297                         {
298                             searchIndex = 0;
299                         }
300                     }
301                     catch (Throwable e)
302                     {
303                         Log.v(TAG, "INPUT STREAM EXCEPTION : " + e.getLocalizedMessage());
304                         // e.printStackTrace();
305                         return (null);
306                     }
307                 }
308                 payload = new Payload(tmpByteArray.toByteArray(), null);
309             }
310         }
311         catch (Exception e)
312         {
313             e.printStackTrace();
314         }
315         return (payload);
316     }
317 }