blob: c6f1b9e215b2baca933590b2bc611f15ab72762e [file] [log] [blame]
package org.frc971;
//Author: Daniel Petti
import java.io.*;
import java.net.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import aos.ChannelImageGetter;
import aos.JPEGDecoder;
import java.nio.channels.SocketChannel;
import java.nio.ByteBuffer;
public class HTTPClient {
//Connects to HTTP Server on robot and receives images
private final static boolean LOCAL_DEBUG = true;
private SocketChannel sock = SocketChannel.open();
private Socket core_sock = sock.socket();
private String LastBoundary = "";
private BufferedReader sock_in;
private PrintWriter sock_out;
private void WriteDebug(String message) {
//small helper function to write debug messages
if (LOCAL_DEBUG)
System.out.println(message);
}
private String ReadtoBoundary(String boundary) {
//reads from socket until it encounters a specific character combination
//if boundary is null, it reads until it runs out of data
StringBuilder recvd = new StringBuilder();
String message = "";
try {
core_sock.setSoTimeout(10000);
}
catch (SocketException e) {
System.err.println("Warning: Could not set socket timeout.");
}
try {
int ret;
while ((ret = sock_in.read()) != -1) {
if (ret == 0) {
//finished receiving
message += recvd.toString();
recvd.setLength(0);
if (boundary == null)
break;
}
else {
recvd.append((char)ret);
if (boundary != null) {
if (message.contains(boundary))
break;
else
continue;
}
}
}
}
catch (InterruptedIOException e) {
System.err.println("Warning: Image receive timed out.");
return null;
}
catch (IOException e) {
System.err.println("Error: Socket read failed.");
return null;
}
return message;
}
public HTTPClient() {
//Initialize socket connection to robot
try {
WriteDebug("Connecting to server...");
sock.connect(new InetSocketAddress("192.168.0.137", 9714));
sock_in = new BufferedReader(new InputStreamReader(core_sock.getInputStream()));
sock_out = new PrintWriter(core_sock.getOutputStream(), true);
//Write headers
//HTTPStreamer does not actually use the headers, so we can just write terminating chars.
WriteDebug("Writing headers...");
sock_out.println("\r\n\r\n");
//Receive headers
WriteDebug("Reading headers...");
ReadtoBoundary("donotcross\r\n");
WriteDebug("Now receiving data.");
}
catch (UnknownHostException e) {
System.err.println("Error: Invalid host.");
System.exit(1);
}
catch (IOException e) {
System.err.println("Error: Socket IO failed.");
System.exit(2);
}
}
public ImageWithTimestamp GetFrame() {
/*//read all current data from socket, in case of processing bottleneck
WriteDebug("Emptying TCP stack...");
String message = ReadtoBoundary(null);
//we must end with a boundary
int len = message.length();
if (message.substring(len - 4, len - 1) != "\r\n\r\n") {
WriteDebug("Boundary was not found. Waiting for boundary...");
message += ReadtoBoundary("\r\n\r\n");
}
//Add the last boundary we cut off to the beginning of our message
message = LastBoundary + message;
//Divide our large message into string separated by boundary beginnings
String[] cut = message.split("\r\n--");
len = cut.length;
//Save the newest boundary, so we can use it later.
LastBoundary = cut[len - 1];
//Keep only our penultimate boundary and the image after it
//NOTE that message is missing its preceding \r\n--
message = cut[len - 2];
cut = message.split("\r\n\r\n");
//NOTE that boundary is now missing its trailing \r\n\r\n
String boundary = cut[0];
String JPEGImage = cut[1];
//extract timestamp in seconds
cut = boundary.split("X-Timestamp: ");
String time_data = cut[1];
boundary = cut[0];
float timestamp = Float.parseFloat(time_data);
//extract size so we can make sure our image data is not corrupted
cut = boundary.split("Content-Length: ");
String size_data = cut[1];
float size = Float.parseFloat(size_data);
assert (size == JPEGImage.length()) : ("Fatal mismatch between actual and expected image size. Check regular expressions.");
byte[] ImageArray = JPEGImage.getBytes();
InputStream in = new ByteArrayInputStream(ImageArray);
try {
BufferedImage bImageFromConvert = ImageIO.read(in);
ImageWithTimestamp to_return = new ImageWithTimestamp();
to_return.image = IplImage.createFrom(bImageFromConvert);
to_return.timestamp = timestamp;
WriteDebug("Image processing successful.");
return to_return;
}
catch (IOException e) {
System.err.println(e.getMessage());
return null;
}
*/
//Use Brian's code to extract an image and timestamp from raw server data.
ImageWithTimestamp final_image = new ImageWithTimestamp();
try {
ChannelImageGetter cgetter = new ChannelImageGetter(sock);
ByteBuffer binary_image = cgetter.getJPEG();
JPEGDecoder decoder = new JPEGDecoder();
boolean sorf = decoder.decode(binary_image, final_image.image);
if (!sorf) {
WriteDebug("Error: JPEG decode failed.");
return null;
}
final_image.timestamp = cgetter.getTimestamp();
return final_image;
}
catch (IOException e) {
WriteDebug("Error: Failed to initialize ChannelImageGetter.");
return null;
}
}
}