blob: c6f1b9e215b2baca933590b2bc611f15ab72762e [file] [log] [blame]
danielp502ec002013-02-19 23:54:14 +00001package org.frc971;
2
3//Author: Daniel Petti
4
5import java.io.*;
6import java.net.*;
7
8import java.awt.image.BufferedImage;
9import javax.imageio.ImageIO;
10
11import com.googlecode.javacv.cpp.opencv_core.IplImage;
12
danielp6eb01d12013-02-20 05:36:09 +000013import aos.ChannelImageGetter;
14import aos.JPEGDecoder;
15
16import java.nio.channels.SocketChannel;
17import java.nio.ByteBuffer;
18
danielp502ec002013-02-19 23:54:14 +000019public class HTTPClient {
20 //Connects to HTTP Server on robot and receives images
21
22 private final static boolean LOCAL_DEBUG = true;
23
danielp6eb01d12013-02-20 05:36:09 +000024 private SocketChannel sock = SocketChannel.open();
25 private Socket core_sock = sock.socket();
danielp502ec002013-02-19 23:54:14 +000026
27 private String LastBoundary = "";
28
danielp6eb01d12013-02-20 05:36:09 +000029 private BufferedReader sock_in;
30 private PrintWriter sock_out;
31
danielp502ec002013-02-19 23:54:14 +000032 private void WriteDebug(String message) {
33 //small helper function to write debug messages
34 if (LOCAL_DEBUG)
35 System.out.println(message);
36 }
37 private String ReadtoBoundary(String boundary) {
38 //reads from socket until it encounters a specific character combination
39 //if boundary is null, it reads until it runs out of data
40 StringBuilder recvd = new StringBuilder();
41 String message = "";
42 try {
danielp6eb01d12013-02-20 05:36:09 +000043 core_sock.setSoTimeout(10000);
danielp502ec002013-02-19 23:54:14 +000044 }
45 catch (SocketException e) {
46 System.err.println("Warning: Could not set socket timeout.");
47 }
48 try {
49 int ret;
50 while ((ret = sock_in.read()) != -1) {
51 if (ret == 0) {
52 //finished receiving
53 message += recvd.toString();
54 recvd.setLength(0);
55 if (boundary == null)
56 break;
57 }
58 else {
59 recvd.append((char)ret);
60 if (boundary != null) {
61 if (message.contains(boundary))
62 break;
63 else
64 continue;
65 }
66 }
67 }
68 }
69 catch (InterruptedIOException e) {
70 System.err.println("Warning: Image receive timed out.");
71 return null;
72 }
73 catch (IOException e) {
74 System.err.println("Error: Socket read failed.");
75 return null;
76 }
77 return message;
78 }
79 public HTTPClient() {
80 //Initialize socket connection to robot
81 try {
82 WriteDebug("Connecting to server...");
danielp6eb01d12013-02-20 05:36:09 +000083 sock.connect(new InetSocketAddress("192.168.0.137", 9714));
84 sock_in = new BufferedReader(new InputStreamReader(core_sock.getInputStream()));
85 sock_out = new PrintWriter(core_sock.getOutputStream(), true);
danielp502ec002013-02-19 23:54:14 +000086 //Write headers
87 //HTTPStreamer does not actually use the headers, so we can just write terminating chars.
88 WriteDebug("Writing headers...");
89 sock_out.println("\r\n\r\n");
90 //Receive headers
91 WriteDebug("Reading headers...");
danielp6eb01d12013-02-20 05:36:09 +000092 ReadtoBoundary("donotcross\r\n");
danielp502ec002013-02-19 23:54:14 +000093 WriteDebug("Now receiving data.");
94 }
95 catch (UnknownHostException e) {
96 System.err.println("Error: Invalid host.");
97 System.exit(1);
98 }
99 catch (IOException e) {
100 System.err.println("Error: Socket IO failed.");
101 System.exit(2);
102 }
103
104 }
105 public ImageWithTimestamp GetFrame() {
danielp6eb01d12013-02-20 05:36:09 +0000106 /*//read all current data from socket, in case of processing bottleneck
danielp502ec002013-02-19 23:54:14 +0000107 WriteDebug("Emptying TCP stack...");
108 String message = ReadtoBoundary(null);
109 //we must end with a boundary
110 int len = message.length();
111 if (message.substring(len - 4, len - 1) != "\r\n\r\n") {
112 WriteDebug("Boundary was not found. Waiting for boundary...");
113 message += ReadtoBoundary("\r\n\r\n");
114 }
115 //Add the last boundary we cut off to the beginning of our message
116 message = LastBoundary + message;
117 //Divide our large message into string separated by boundary beginnings
118 String[] cut = message.split("\r\n--");
119 len = cut.length;
120 //Save the newest boundary, so we can use it later.
121 LastBoundary = cut[len - 1];
122 //Keep only our penultimate boundary and the image after it
123 //NOTE that message is missing its preceding \r\n--
124 message = cut[len - 2];
125 cut = message.split("\r\n\r\n");
126 //NOTE that boundary is now missing its trailing \r\n\r\n
127 String boundary = cut[0];
128 String JPEGImage = cut[1];
129 //extract timestamp in seconds
130 cut = boundary.split("X-Timestamp: ");
131 String time_data = cut[1];
132 boundary = cut[0];
133 float timestamp = Float.parseFloat(time_data);
134 //extract size so we can make sure our image data is not corrupted
135 cut = boundary.split("Content-Length: ");
136 String size_data = cut[1];
137 float size = Float.parseFloat(size_data);
danielp305cb512013-02-20 01:37:07 +0000138 assert (size == JPEGImage.length()) : ("Fatal mismatch between actual and expected image size. Check regular expressions.");
danielp502ec002013-02-19 23:54:14 +0000139 byte[] ImageArray = JPEGImage.getBytes();
140 InputStream in = new ByteArrayInputStream(ImageArray);
141 try {
142 BufferedImage bImageFromConvert = ImageIO.read(in);
143 ImageWithTimestamp to_return = new ImageWithTimestamp();
144 to_return.image = IplImage.createFrom(bImageFromConvert);
145 to_return.timestamp = timestamp;
146 WriteDebug("Image processing successful.");
147 return to_return;
148 }
149 catch (IOException e) {
150 System.err.println(e.getMessage());
151 return null;
152 }
danielp6eb01d12013-02-20 05:36:09 +0000153 */
154 //Use Brian's code to extract an image and timestamp from raw server data.
155 ImageWithTimestamp final_image = new ImageWithTimestamp();
156 try {
157 ChannelImageGetter cgetter = new ChannelImageGetter(sock);
158 ByteBuffer binary_image = cgetter.getJPEG();
159 JPEGDecoder decoder = new JPEGDecoder();
160 boolean sorf = decoder.decode(binary_image, final_image.image);
161 if (!sorf) {
162 WriteDebug("Error: JPEG decode failed.");
163 return null;
164 }
165 final_image.timestamp = cgetter.getTimestamp();
166 return final_image;
167 }
168 catch (IOException e) {
169 WriteDebug("Error: Failed to initialize ChannelImageGetter.");
170 return null;
171 }
danielp502ec002013-02-19 23:54:14 +0000172 }
173}