Cleaning up benchmarks and drivers code.
[iot2.git] / benchmarks / drivers / Java / AmcrestCamera / AmcrestCamera.java
1 package iotcode.AmcrestCamera;
2
3 // IoT Packages
4 import iotcode.annotation.*;
5 import iotcode.interfaces.*;
6 import iotruntime.IoTHTTP;
7 import iotruntime.slave.IoTSet;
8 import iotruntime.slave.IoTDeviceAddress;
9
10 // Standard Java Packages
11 import java.io.IOException;
12 import java.io.DataInputStream;
13 import java.io.InputStream;
14 import java.io.BufferedInputStream;
15 import java.io.ByteArrayInputStream;
16 import java.io.IOException;
17 import java.io.ByteArrayOutputStream;
18 import java.io.File;
19 import java.awt.image.BufferedImage;
20 import java.awt.image.ColorModel;
21 import java.awt.image.WritableRaster;
22 import java.awt.image.BufferedImage;
23 import javax.imageio.ImageIO;
24 import java.util.Base64;
25 import java.util.Arrays;
26 import java.util.Date;
27 import java.util.List;
28 import java.util.ArrayList;
29 import java.util.Set;
30 import java.util.HashSet;
31 import java.util.concurrent.locks.Lock;
32 import java.util.concurrent.locks.ReadWriteLock;
33 import java.util.concurrent.locks.ReentrantReadWriteLock;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.Iterator;
36 import javax.imageio.ImageIO;
37 import java.util.concurrent.CopyOnWriteArrayList;
38 import java.util.concurrent.Semaphore;
39
40 // RMI Packages
41 import java.rmi.Remote;
42 import java.rmi.RemoteException;
43
44 public class AmcrestCamera implements Camera {
45
46         /*******************************************************************************************************************************************
47         **
48         **  Variables
49         **
50         *******************************************************************************************************************************************/
51         private String credentialUsername = "";
52         private String credentialPassword = "";
53         private DataInputStream dataInStream = null;
54         private boolean isStreamConnected = false;
55         private byte[] latestImage = null;
56         private ReadWriteLock imageReadWriteLock = new ReentrantReadWriteLock();
57         private Lock imageReadLock = imageReadWriteLock.readLock();
58         private Lock imageWriteLock = imageReadWriteLock.writeLock();
59         private AtomicBoolean newFrameAvailable = new AtomicBoolean(false);
60         private ReadWriteLock timestampReadWriteLock = new ReentrantReadWriteLock();
61         private Lock timestampReadLock = timestampReadWriteLock.readLock();
62         private Lock timestampWriteLock = timestampReadWriteLock.writeLock();
63         private Date latestImageTimestamp = null;
64         private List <CameraSmartCallback> callbackList =
65             new CopyOnWriteArrayList <CameraSmartCallback> ();
66         private AtomicBoolean doEnd = new AtomicBoolean(false);
67         private IoTDeviceAddress deviceAddress = null;
68         private AtomicBoolean didInit = new AtomicBoolean();
69         private AtomicBoolean didStart = new AtomicBoolean();
70         static Semaphore settingsSettings = new Semaphore(1);
71
72         /*******************************************************************************************************************************************
73         **
74         **  Threads
75         **
76         *******************************************************************************************************************************************/
77         private Thread callbackThread = null;
78         private Thread workerThread = null;
79
80
81         /*******************************************************************************************************************************************
82         **
83         **  IoT Sets and Relations
84         **
85         *******************************************************************************************************************************************/
86
87         // IoTSet of Device Addresses.
88         // Will be filled with only 1 address.
89         @config private IoTSet<IoTDeviceAddress> cam_addresses;
90
91         public AmcrestCamera(String _credentialUsername, String _credentialPassword, IoTSet<IoTDeviceAddress> _camAddresses) throws RemoteException {
92                 credentialUsername = _credentialUsername;
93                 credentialPassword = _credentialPassword;
94                 cam_addresses = _camAddresses;
95         }
96
97         public AmcrestCamera(String _credentialUsername, String _credentialPassword) throws RemoteException {
98                 credentialUsername = _credentialUsername;
99                 credentialPassword = _credentialPassword;
100         }
101
102         /*******************************************************************************************************************************************
103         **
104         **  Camera Interface Methods
105         **
106         *******************************************************************************************************************************************/
107
108         public byte[] getLatestFrame() {
109
110                 byte[] newImage = null;
111
112                 imageReadLock.lock();
113                 try {
114                         if (latestImage != null) {
115                                 newImage = Arrays.copyOf(latestImage, latestImage.length);
116                         }
117                 } catch (Exception x) {
118                         x.printStackTrace();
119                 }
120                 imageReadLock.unlock();
121
122                 return newImage;
123         }
124
125         public long getTimestamp() {
126                 timestampReadLock.lock();
127                 Date ret = (Date)latestImageTimestamp.clone();
128                 timestampReadLock.unlock();
129                 long retLong = ret.getTime();
130                 return retLong;
131         }
132
133         public void registerCallback(CameraSmartCallback _callbackTo) {
134                 callbackList.add(_callbackTo);
135         }
136
137         public boolean setFPS(int _fps) {
138                 try {
139                         settingsSettings.acquire();
140
141                         String camUrlString = "/cgi-bin/configManager.cgi?action=setConfig&Encode[0].MainFormat[0].Video.FPS=" + Integer.toString(_fps);
142
143                         try {
144
145                                 String credsPreBase64 = credentialUsername + ":" + credentialPassword;
146                                 String credsBase64 = Base64.getEncoder().encodeToString(credsPreBase64.getBytes("utf-8"));
147                                 String httpAuthCredentials = "Basic " + credsBase64;
148
149                                 IoTHTTP httpConnection = new IoTHTTP(deviceAddress);
150                                 httpConnection.setURL(camUrlString);
151                                 httpConnection.openConnection();
152                                 httpConnection.setDoInput(true);
153                                 httpConnection.setRequestProperty("Authorization", httpAuthCredentials);
154                                 httpConnection.connect();
155                                 
156                                 InputStream is = httpConnection.getInputStream();
157                                 BufferedInputStream bis = new BufferedInputStream(is);
158                                 DataInputStream din = new DataInputStream(bis);
159                                 
160                                 // wait for a response
161                                 try {
162                                         Thread.sleep(1000);
163                                 } catch (InterruptedException ie) {
164                                 }
165
166                                 byte[] byteBuf = new byte[100];
167                                 try {
168                                         int r = din.read(byteBuf, 0, byteBuf.length);
169                                         String retString = new String(byteBuf);
170
171                                         if (!retString.substring(0, 2).equals("OK")) {
172                                                 httpConnection.disconnect();
173                                                 return false;
174                                         }
175
176                                 } catch (Exception e) {
177                                         httpConnection.disconnect();
178                                         return false;
179                                         // e.printStackTrace();
180                                 }
181                                 
182                                 httpConnection.disconnect();
183                         } catch (IOException e) {
184                                 return false;
185                         } catch (Exception e) {
186                                 return false;
187                         }
188                 } catch (Exception e) {
189                         e.printStackTrace();
190                 }
191                 settingsSettings.release();
192
193                 return true;
194         }
195
196         public int getMaxFPS() {
197                 // Hard coded since this is hardware dependant
198                 return 30;
199         }
200
201         public int getMinFPS() {
202                 // Hard coded since this is hardware dependant
203                 return 5;
204         }
205
206         public List<Resolution> getSupportedResolutions() {
207
208                 // Hard coded since this is hardware dependant
209                 List<Resolution> ret = new ArrayList<Resolution>();
210                 ret.add(Resolution.RES_1080P);
211                 ret.add(Resolution.RES_720P);
212                 ret.add(Resolution.RES_VGA);
213                 return ret;
214         }
215
216         public boolean setResolution(Resolution _res) {
217
218                 try {
219                         settingsSettings.acquire();
220
221
222                         String camUrlString = "/cgi-bin/configManager.cgi?action=setConfig";
223
224                         if (_res == Resolution.RES_1080P) {
225                                 camUrlString += "&Encode[0].MainFormat[0].Video.Height=1080&Encode[0].MainFormat[0].Video.Width=1920";
226
227                         } else if (_res == Resolution.RES_720P) {
228                                 camUrlString += "&Encode[0].MainFormat[0].Video.Height=720&Encode[0].MainFormat[0].Video.Width=1280";
229
230                         } else if (_res == Resolution.RES_VGA) {
231                                 camUrlString += "&Encode[0].MainFormat[0].Video.Height=480&Encode[0].MainFormat[0].Video.Width=640";
232                         }
233
234                         try {
235
236                                 String credsPreBase64 = credentialUsername + ":" + credentialPassword;
237                                 String credsBase64 = Base64.getEncoder().encodeToString(credsPreBase64.getBytes("utf-8"));
238                                 String httpAuthCredentials = "Basic " + credsBase64;
239
240                                 IoTHTTP httpConnection = new IoTHTTP(deviceAddress);
241                                 httpConnection.setURL(camUrlString);
242                                 httpConnection.openConnection();
243                                 httpConnection.setDoInput(true);
244                                 httpConnection.setRequestProperty("Authorization", httpAuthCredentials);
245                                 httpConnection.connect();
246
247                                 InputStream is = httpConnection.getInputStream();
248                                 BufferedInputStream bis = new BufferedInputStream(is);
249                                 DataInputStream din = new DataInputStream(bis);
250
251                                 // wait for a response
252                                 try {
253                                         Thread.sleep(1000);
254                                 } catch (InterruptedException ie) {
255                                 }
256
257                                 byte[] byteBuf = new byte[100];
258                                 try {
259                                         int r = din.read(byteBuf, 0, byteBuf.length);
260                                         String retString = new String(byteBuf);
261
262                                         if (!retString.substring(0, 2).equals("OK")) {
263                                                 httpConnection.disconnect();
264                                                 return false;
265                                         }
266
267                                 } catch (Exception e) {
268                                         httpConnection.disconnect();
269                                         return false;
270                                         // e.printStackTrace();
271                                 }
272
273                                 httpConnection.disconnect();
274                         } catch (IOException e) {
275                                 return false;
276                         } catch (Exception e) {
277                                 return false;
278                         }
279                 } catch (Exception e) {
280                         e.printStackTrace();
281                 }
282
283                 settingsSettings.release();
284
285                 return true;
286         }
287
288         public void start() {
289
290                 if (didStart.compareAndSet(false, true) == false) {
291                         return; // already started
292                 }
293
294                 doEnd.set(false);
295
296                 if (!streamConnect()) {
297                         return;
298                 }
299
300                 callbackThread = new Thread(new Runnable() {
301                         public void run() {
302                                 doCallbacks();
303                         }
304                 });
305                 callbackThread.start();
306
307                 workerThread = new Thread(new Runnable() {
308                         public void run() {
309                                 doWork();
310                         }
311                 });
312                 workerThread.start();
313         }
314
315         public void stop() {
316                 if (didStart.compareAndSet(true, false) == false) {
317                         return; // already stopped
318                 }
319
320                 doEnd.set(true);
321
322                 try {
323                         callbackThread.join();
324                         workerThread.join();
325                 } catch (Exception e) {
326                         e.printStackTrace();
327                 }
328
329                 streamDisconnect();
330         }
331
332         public void init() {
333                 if (didInit.compareAndSet(false, true) == false) {
334                         return; // already init
335                 }
336
337                 // get the device address and save it for later use when creating HTTP connections
338                 Iterator itr = cam_addresses.iterator();
339                 deviceAddress = (IoTDeviceAddress)itr.next();
340
341                 System.out.println("Address: " + deviceAddress.getCompleteAddress());
342         }
343
344         /*******************************************************************************************************************************************
345         **
346         **  Helper Methods
347         **
348         *******************************************************************************************************************************************/
349         private byte[] readFromStream(int num) {
350                 byte[] byteBuf = new byte[num];
351                 try {
352                         dataInStream.readFully(byteBuf, 0, byteBuf.length);
353                 } catch (Exception e) {
354                         e.printStackTrace();
355                 }
356
357                 return byteBuf;
358         }
359
360         private void findBoundry() {
361                 String boundary = "**************";
362                 while (true) {
363                         byte b = readFromStream(1)[0];
364                         boundary = boundary.substring(1);
365                         boundary += (char)b;
366
367                         if (boundary.equals("--myboundary\r\n")) {
368                                 break;
369                         }
370                 }
371         }
372
373         private String getLine() {
374                 String line = "";
375                 while (true) {
376                         byte b = readFromStream(1)[0];
377                         char c = (char)b;
378
379                         if (c == '\n') {
380                                 break;
381                         } else if (c != '\r') {
382                                 line += c;
383                         }
384                 }
385
386                 return line;
387         }
388
389         private BufferedImage parseImage() {
390
391                 findBoundry();
392
393                 String contentTypeString = getLine();
394                 String contentLengthString = getLine();
395
396                 // remove the new line characters \r\n
397                 readFromStream(2);
398
399                 int imageDataLength = Integer.parseInt(contentLengthString.substring(16));
400
401                 byte[] imageDataBuf = readFromStream(imageDataLength);
402
403                 // remove the new line characters \r\n
404                 readFromStream(2);
405
406
407                 try {
408                         InputStream imageInStream = new ByteArrayInputStream(imageDataBuf);
409                         return ImageIO.read(imageInStream);
410
411                 } catch (Exception e) {
412                         e.printStackTrace();
413                         System.out.println("Has Exception");
414
415                 }
416
417                 return null;
418         }
419
420         private boolean streamConnect() {
421
422                 try {
423
424                         String credsPreBase64 = credentialUsername + ":" + credentialPassword;
425                         String credsBase64 = Base64.getEncoder().encodeToString(credsPreBase64.getBytes("utf-8"));
426                         String httpAuthCredentials = "Basic " + credsBase64;
427
428                         IoTHTTP httpConnection = new IoTHTTP(deviceAddress);
429                         httpConnection.setURL("/cgi-bin/mjpg/video.cgi?channel=0&subtype=1");
430                         //httpConnection.setURL("/cgi-bin/mjpg/video.cgi?channel=0&subtype=1", credentialUsername, credentialPassword);
431                         httpConnection.openConnection();
432                         httpConnection.setDoInput(true);
433                         httpConnection.setRequestProperty("Authorization", httpAuthCredentials);
434                         httpConnection.connect();
435
436                         InputStream is = httpConnection.getInputStream();
437                         BufferedInputStream bis = new BufferedInputStream(is);
438                         dataInStream = new DataInputStream(bis);
439
440                         isStreamConnected = true;
441
442                 } catch (IOException e) {
443                         isStreamConnected = false;
444
445                 } catch (Exception e) {
446                         isStreamConnected = false;
447                 }
448
449                 return isStreamConnected;
450         }
451
452         private void streamDisconnect() {
453                 try {
454                         if (isStreamConnected) {
455                                 dataInStream.close();
456                                 isStreamConnected = false;
457                         }
458                 } catch (Exception e) {
459                 }
460         }
461
462         private void doCallbacks() {
463
464                 while (!doEnd.get()) {
465                         if (newFrameAvailable.compareAndSet(true, false)) {
466
467                                 for (CameraSmartCallback c : callbackList) {
468
469                                         c.newCameraFrameAvailable(this.getLatestFrame(), this.getTimestamp());
470                                         //c.newCameraFrameAvailable(this);
471                                 }
472                         } else {
473
474                                 // Sleep for 15 millisec to give time for new frame to arrive
475                                 try {
476                                         Thread.sleep(15);
477                                 } catch (InterruptedException ie) {
478                                 }
479                         }
480                 }
481
482         }
483
484         private void doWork() {
485
486                 // parse the images that are loaded into the buffer
487                 while (!doEnd.get()) {
488
489                         BufferedImage img = parseImage();
490
491                         if (img != null) {
492
493                                 timestampWriteLock.lock();
494                                 latestImageTimestamp = new Date();
495                                 timestampWriteLock.unlock();
496
497                                 imageWriteLock.lock();
498
499                                 try {
500                                         ByteArrayOutputStream baos = new ByteArrayOutputStream();
501                                         ImageIO.write(img, "jpg", baos);
502                                         baos.flush();
503                                         latestImage = baos.toByteArray();
504                                         baos.close();
505
506                                 } catch (Exception e) {
507
508                                 }
509                                 imageWriteLock.unlock();
510
511                                 newFrameAvailable.set(true);
512                         }
513
514                         try {
515                                 if (dataInStream.available() > 120000) {
516                                         dataInStream.skip(120000);
517                                 }
518                         } catch (Exception e) {
519                         }
520                 }
521
522         }
523         
524         /* TODO: Uncomment this part to do camera test
525         public static void main(String[] args) throws Exception {
526
527                 System.out.println("Running AmcrestCamera!");
528                 
529                 // The constructor for IoTDeviceAddress needs to be changed temporarily to make this
530                 // to work.
531                 IoTDeviceAddress iotDevAdd = new IoTDeviceAddress(args[0], 12345, 80, false, false);
532                 Set<IoTDeviceAddress> set = new HashSet<IoTDeviceAddress>();
533                 set.add(iotDevAdd);
534                 IoTSet<IoTDeviceAddress> iotset = new IoTSet<IoTDeviceAddress>(set);
535         
536                 AmcrestCamera cam = new AmcrestCamera(args[1], args[2], iotset);
537                 cam.init();
538                 cam.setFPS(15);
539                 cam.setResolution(Resolution.RES_VGA);
540                 cam.start();
541
542             while (true) {
543
544             }
545
546         }*/
547 }
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563