1 package edu.wpi.first.smartdashboard.gui.elements;
3 import edu.wpi.first.smartdashboard.gui.DashboardPrefs;
4 import edu.wpi.first.smartdashboard.gui.StaticWidget;
5 import edu.wpi.first.smartdashboard.properties.IntegerProperty;
6 import edu.wpi.first.smartdashboard.properties.Property;
7 import edu.wpi.first.smartdashboard.properties.StringProperty;
10 import java.awt.Dimension;
11 import java.awt.Graphics;
12 import java.awt.Graphics2D;
13 import java.awt.geom.AffineTransform;
14 import java.awt.image.BufferedImage;
15 import java.io.ByteArrayInputStream;
16 import java.io.ByteArrayOutputStream;
17 import java.io.InputStream;
19 import java.net.URLConnection;
21 import javax.imageio.ImageIO;
25 * @author Greg Granito
27 public class VideoStreamViewerExtension extends StaticWidget {
29 public static final String NAME = "Simple Camera Viewer";
32 private static final int[] START_BYTES = new int[]{0xFF, 0xD8};
33 private static final int[] END_BYTES = new int[]{0xFF, 0xD9};
35 private boolean ipChanged = true;
36 private String ipString = null;
37 private double rotateAngleRad = 0;
38 private long lastFPSCheck = 0;
39 private int lastFPS = 0;
40 private int fpsCounter = 0;
41 public class BGThread extends Thread {
43 boolean destroyed = false;
46 super("Camera Viewer Background");
52 URLConnection connection = null;
53 InputStream stream = null;
54 ByteArrayOutputStream imageBuffer = new ByteArrayOutputStream();
57 System.out.println("Connecting to camera");
59 URL url = new URL("http://"+ipString+"/mjpg/video.mjpg");
60 connection = url.openConnection();
61 connection.setReadTimeout(250);
62 stream = connection.getInputStream();
64 while(!destroyed && !ipChanged){
65 while(System.currentTimeMillis()-lastRepaint<10){
66 stream.skip(stream.available());
69 stream.skip(stream.available());
72 for(int i = 0; i<START_BYTES.length;){
73 int b = stream.read();
79 for(int i = 0; i<START_BYTES.length;++i)
80 imageBuffer.write(START_BYTES[i]);
82 for(int i = 0; i<END_BYTES.length;){
83 int b = stream.read();
92 if(System.currentTimeMillis()-lastFPSCheck>500){
93 lastFPSCheck = System.currentTimeMillis();
94 lastFPS = fpsCounter*2;
98 lastRepaint = System.currentTimeMillis();
99 ByteArrayInputStream tmpStream = new ByteArrayInputStream(imageBuffer.toByteArray());
100 imageToDraw = ImageIO.read(tmpStream);
101 System.out.println(System.currentTimeMillis()-lastRepaint);
105 } catch(Exception e){
114 } catch (InterruptedException ex) {}
121 public void destroy() {
125 private BufferedImage imageToDraw;
126 private BGThread bgThread = new BGThread();
127 public final StringProperty ipProperty = new StringProperty(this, "Camera IP Address or mDNS name", "axis-camera.local");
128 public final IntegerProperty rotateProperty = new IntegerProperty(this, "Degrees Rotation", 0);
132 setPreferredSize(new Dimension(100, 100));
133 ipString = ipProperty.getSaveValue();
134 rotateAngleRad = Math.toRadians(rotateProperty.getValue());
141 public void propertyChanged(Property property) {
142 if (property == ipProperty) {
143 ipString = ipProperty.getSaveValue();
146 if (property == rotateProperty) {
147 rotateAngleRad = Math.toRadians(rotateProperty.getValue());
153 public void disconnect() {
159 protected void paintComponent(Graphics g) {
160 BufferedImage drawnImage = imageToDraw;
162 if (drawnImage != null) {
163 // cast the Graphics context into a Graphics2D
164 Graphics2D g2d = (Graphics2D)g;
166 // get the existing Graphics transform and copy it so that we can perform scaling and rotation
167 AffineTransform origXform = g2d.getTransform();
168 AffineTransform newXform = (AffineTransform)(origXform.clone());
170 // find the center of the original image
171 int origImageWidth = drawnImage.getWidth();
172 int origImageHeight = drawnImage.getHeight();
173 int imageCenterX = origImageWidth/2;
174 int imageCenterY = origImageHeight/2;
176 // perform the desired scaling
177 double panelWidth = getBounds().width;
178 double panelHeight = getBounds().height;
179 double panelCenterX = panelWidth/2.0;
180 double panelCenterY = panelHeight/2.0;
181 double rotatedImageWidth = origImageWidth * Math.abs(Math.cos(rotateAngleRad)) + origImageHeight * Math.abs(Math.sin(rotateAngleRad));
182 double rotatedImageHeight = origImageWidth * Math.abs(Math.sin(rotateAngleRad)) + origImageHeight * Math.abs(Math.cos(rotateAngleRad));
184 // compute scaling needed
185 double scale = Math.min(panelWidth / rotatedImageWidth, panelHeight / rotatedImageHeight);
187 // set the transform before drawing the image
188 // 1 - translate the origin to the center of the panel
189 // 2 - perform the desired rotation (rotation will be about origin)
190 // 3 - perform the desired scaling (will scale centered about origin)
191 newXform.translate(panelCenterX, panelCenterY);
192 newXform.rotate(rotateAngleRad);
193 newXform.scale(scale, scale);
194 g2d.setTransform(newXform);
196 // draw image so that the center of the image is at the "origin"; the transform will take care of the rotation and scaling
197 g2d.drawImage(drawnImage, -imageCenterX, -imageCenterY, null);
199 // restore the original transform
200 g2d.setTransform(origXform);
202 g.setColor(Color.PINK);
203 g.drawString("FPS: "+lastFPS, 10, 10);
205 g.setColor(Color.PINK);
206 g.fillRect(0, 0, getBounds().width, getBounds().height);
207 g.setColor(Color.BLACK);
208 g.drawString("NO CONNECTION", 10, 10);