From 7b224a9572eabfa6c1924574b04c721f75321dab Mon Sep 17 00:00:00 2001 From: Sam Carlberg Date: Thu, 9 Nov 2017 15:28:50 -0500 Subject: [PATCH] Use InetAddress.localhost() for getting hostname, add test for mat copy --- .../composite/PublishVideoOperation.java | 63 +++++----------- .../composite/PublishVideoOperationTest.java | 74 +++++++++++++++++++ 2 files changed, 93 insertions(+), 44 deletions(-) create mode 100644 core/src/test/java/edu/wpi/grip/core/operations/composite/PublishVideoOperationTest.java diff --git a/core/src/main/java/edu/wpi/grip/core/operations/composite/PublishVideoOperation.java b/core/src/main/java/edu/wpi/grip/core/operations/composite/PublishVideoOperation.java index bb1cdf43e9..fe1092761c 100644 --- a/core/src/main/java/edu/wpi/grip/core/operations/composite/PublishVideoOperation.java +++ b/core/src/main/java/edu/wpi/grip/core/operations/composite/PublishVideoOperation.java @@ -7,6 +7,7 @@ import edu.wpi.grip.core.sockets.SocketHints; import edu.wpi.grip.core.util.Icon; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -17,15 +18,12 @@ import edu.wpi.first.wpilibj.networktables.NetworkTable; import edu.wpi.first.wpilibj.tables.ITable; -import org.apache.commons.lang.SystemUtils; import org.bytedeco.javacpp.opencv_core; import org.opencv.core.Mat; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; import java.lang.reflect.Field; -import java.util.Arrays; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.Deque; import java.util.LinkedList; import java.util.List; @@ -115,8 +113,16 @@ public PublishVideoOperation(InputSocket.Factory inputSocketFactory) { server.setSource(serverSource); ourTable = cameraPublisherTable.getSubTable("GRIP-" + totalStepCount); - ourTable.putStringArray("streams", - new String[]{"mjpeg:http://" + getHostName() + ":" + ourPort + "/?action=stream"}); + try { + InetAddress localHost = InetAddress.getLocalHost(); + ourTable.putStringArray("streams", + new String[]{ + generateStreamUrl(localHost.getHostName(), ourPort), + generateStreamUrl(localHost.getHostAddress(), ourPort) + }); + } catch (UnknownHostException e) { + ourTable.putStringArray("streams", new String[0]); + } } else { server = null; serverSource = null; @@ -177,6 +183,10 @@ public synchronized void cleanUp() { } } + private static String generateStreamUrl(String host, int port) { + return String.format("mjpeg:http://%s:%d/?action=stream", host, port); + } + /** * Copies the data from a JavaCV Mat wrapper object into an OpenCV Mat wrapper object so it's * usable by the {@link CvSource} for this operation. @@ -195,7 +205,8 @@ public synchronized void cleanUp() { * @param openCvMat the OpenCV Mat wrapper object to copy into * @throws RuntimeException if the OpenCV native pointer could not be set */ - private static void copyJavaCvToOpenCvMat(opencv_core.Mat javaCvMat, Mat openCvMat) + @VisibleForTesting + static void copyJavaCvToOpenCvMat(opencv_core.Mat javaCvMat, Mat openCvMat) throws RuntimeException { // Make the OpenCV Mat object point to the same block of memory as the JavaCV object. // This requires no data transfers or copies and is O(1) instead of O(n) @@ -211,40 +222,4 @@ private static void copyJavaCvToOpenCvMat(opencv_core.Mat javaCvMat, Mat openCvM } } - /** - * Multi platform method for getting the hostname of the local computer. cscore's - * {@link CameraServerJNI#getHostname() getHostName() function} only works on Linux, so we need to - * implement the method for Windows and Mac ourselves. - */ - private static String getHostName() { - if (SystemUtils.IS_OS_WINDOWS) { - // Use the Windows `hostname` command-line utility - // This will return a single line of text containing the hostname, no parsing required - ProcessBuilder builder = new ProcessBuilder("hostname"); - Process hostname; - try { - hostname = builder.start(); - } catch (IOException e) { - logger.log(Level.WARNING, "Could not start hostname process", e); - return ""; - } - try (BufferedReader in = - new BufferedReader(new InputStreamReader(hostname.getInputStream()))) { - return in.readLine() + ".local"; - } catch (IOException e) { - logger.log(Level.WARNING, "Could not read the hostname process output", e); - return ""; - } - } else if (SystemUtils.IS_OS_LINUX) { - // cscore already defines it for linux - return CameraServerJNI.getHostname(); - } else if (SystemUtils.IS_OS_MAC) { - // todo - return "TODO-MAC"; - } else { - throw new UnsupportedOperationException( - "Unsupported operating system " + System.getProperty("os.name")); - } - } - } diff --git a/core/src/test/java/edu/wpi/grip/core/operations/composite/PublishVideoOperationTest.java b/core/src/test/java/edu/wpi/grip/core/operations/composite/PublishVideoOperationTest.java new file mode 100644 index 0000000000..263b2ef29a --- /dev/null +++ b/core/src/test/java/edu/wpi/grip/core/operations/composite/PublishVideoOperationTest.java @@ -0,0 +1,74 @@ +package edu.wpi.grip.core.operations.composite; + +import edu.wpi.grip.util.Files; + +import org.bytedeco.javacpp.opencv_core; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opencv.core.Mat; + +import java.nio.ByteBuffer; + +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +public class PublishVideoOperationTest { + + @BeforeClass + public static void initialize() { + // Make sure the OpenCV JNI is loaded + blackHole(PublishVideoOperation.DESCRIPTION); + } + + @Test + public void testCopyJavaCvToOpenCvMat_GompeiImage() { + // given + final Mat openCvMat = new Mat(); + + // then (with the GRIP logo) + test(Files.imageFile.createMat(), openCvMat); + + // and again (with gompei) to confirm that changing the input will be cleanly copied to the + // output image and cleanly overwrite any existing data + test(Files.gompeiJpegFile.createMat(), openCvMat); + } + + private static void test(opencv_core.Mat javaCvMat, Mat openCvMat) { + // when + PublishVideoOperation.copyJavaCvToOpenCvMat(javaCvMat, openCvMat); + + // then + + // test the basic properties (same size, type, etc.) + assertEquals("Wrong width", javaCvMat.cols(), openCvMat.cols()); + assertEquals("Wrong height", javaCvMat.rows(), openCvMat.rows()); + assertEquals("Wrong type", javaCvMat.type(), openCvMat.type()); + assertEquals("Wrong channel amount", javaCvMat.channels(), openCvMat.channels()); + assertEquals("Wrong bit depth", javaCvMat.depth(), openCvMat.depth()); + + // test the raw data bytes - they should be identical + final int width = javaCvMat.cols(); + final int height = javaCvMat.rows(); + final int channels = javaCvMat.channels(); + + final ByteBuffer buffer = javaCvMat.createBuffer(); + assertThat("JavaCV byte buffer is smaller than expected!", + buffer.capacity(), greaterThanOrEqualTo(width * height * channels)); + + final byte[] javaCvData = new byte[width * height * channels]; + buffer.get(javaCvData); + + final byte[] openCvData = new byte[width * height * channels]; + openCvMat.get(0, 0, openCvData); + + assertArrayEquals("Wrong data bytes", javaCvData, openCvData); + } + + // workaround for FindBugs reporting unused variables + private static void blackHole(Object ignore) { + // nop + } + +}