Added a device listener
authorTomas Wenström <tomas.wenstrom@gmail.com>
Tue, 21 Mar 2017 21:59:29 +0000 (22:59 +0100)
committerTomas Wenström <tomas.wenstrom@gmail.com>
Wed, 22 Mar 2017 19:41:47 +0000 (20:41 +0100)
config.properties
src/kaka/cakelight/Configuration.java
src/kaka/cakelight/FrameGrabber.java
src/kaka/cakelight/VideoDeviceListener.java [new file with mode: 0644]
src/kaka/cakelight/VideoMode.java

index cb1d685..ad972c2 100644 (file)
@@ -1,6 +1,5 @@
 # default settings
 
-video.device=/dev/video2
 video.width=720
 video.height=576
 video.bpp=2
index 30308e2..0d7bf5b 100644 (file)
@@ -56,14 +56,12 @@ public class Configuration {
     }
 
     public class VideoConfiguration {
-        public String device;
         public int width;
         public int height;
         public int bpp;
         public CropConfiguration crop;
 
         private VideoConfiguration(Properties prop) {
-            device = get(prop, "video.device", "/dev/video0");
             width = Integer.parseInt(get(prop, "video.width", "720"));
             height = Integer.parseInt(get(prop, "video.height", "576"));
             bpp = Integer.parseInt(get(prop, "video.bpp", "2"));
index 8fbb16f..92fd50a 100644 (file)
@@ -14,10 +14,10 @@ public class FrameGrabber implements Closeable {
     private FrameGrabber() {
     }
 
-    public static FrameGrabber from(Configuration config) {
+    public static FrameGrabber from(File videoDevice, Configuration config) {
         FrameGrabber fg = new FrameGrabber();
         fg.config = config;
-        fg.file = new File(config.video.device);
+        fg.file = videoDevice;
         fg.bytesPerFrame = config.video.width * config.video.height * config.video.bpp;
         fg.prepare();
         return fg;
diff --git a/src/kaka/cakelight/VideoDeviceListener.java b/src/kaka/cakelight/VideoDeviceListener.java
new file mode 100644 (file)
index 0000000..23c0b02
--- /dev/null
@@ -0,0 +1,50 @@
+package kaka.cakelight;
+
+import java.io.File;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+import static kaka.cakelight.Main.log;
+
+public class VideoDeviceListener {
+    private Thread thread;
+    private Consumer<Optional<File>> changeConsumer;
+    private File lastDevice = null;
+
+    public void startListening() {
+       thread = new Thread() {
+           public void run() {
+               try {
+                   while (!isInterrupted()) {
+                       Optional<File> device = findVideoDevice();
+                       if (!device.equals(Optional.ofNullable(lastDevice))) {
+                           log("Video device change: %s", device.map(File::getAbsolutePath).orElse("none"));
+                           changeConsumer.accept(device);
+                           lastDevice = device.orElseGet(() -> null);
+                       }
+                       Thread.sleep(1000);
+                   }
+               } catch (InterruptedException e) {
+               }
+           }
+       };
+       thread.start();
+    }
+
+    public void stopListening() {
+        thread.interrupt();
+    }
+
+    private Optional<File> findVideoDevice() {
+       File[] files = new File("/dev").listFiles((dir, name) -> name.matches("video[0-9]+"));
+       if (files == null || files.length == 0) {
+           return Optional.empty();
+       } else {
+           return Optional.of(files[0]);
+       }
+    }
+
+    public void onVideoDeviceChange(Consumer<Optional<File>> consumer) {
+       changeConsumer = consumer;
+    }
+}
index 53cf09b..e0dc386 100644 (file)
@@ -1,33 +1,38 @@
 package kaka.cakelight;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.Optional;
 import java.util.function.Consumer;
 
-import static kaka.cakelight.Main.log;
-import static kaka.cakelight.Main.timeIt;
-
-public class VideoMode implements Mode {
+public class VideoMode implements Mode, Consumer<Optional<File>> {
     private Configuration config;
     private Thread thread;
     private Consumer<Frame> frameConsumer;
+    private VideoDeviceListener deviceListener;
+
+    public VideoMode() {
+        deviceListener = new VideoDeviceListener();
+        deviceListener.onVideoDeviceChange(this);
+    }
 
     @Override
     public void enter(Configuration config) {
         this.config = config;
-        startGrabberThread();
+        deviceListener.startListening();
     }
 
     @Override
     public void exit() {
         thread.interrupt();
+        deviceListener.stopListening();
     }
 
-    private void startGrabberThread() {
+    private void startGrabberThread(File videoDevice) {
         assert frameConsumer != null;
         thread = new Thread() {
             public void run() {
-                try (FrameGrabber grabber = FrameGrabber.from(config)) {
+                try (FrameGrabber grabber = FrameGrabber.from(videoDevice, config)) {
                     while (!isInterrupted()) {
 //                        Optional<Frame> frame = grabber.grabFrame();
                         grabber.grabFrame().ifPresent(frameConsumer);
@@ -46,4 +51,13 @@ public class VideoMode implements Mode {
     public void onFrame(Consumer<Frame> consumer) {
         frameConsumer = consumer;
     }
+
+    @Override
+    public void accept(Optional<File> videoDevice) {
+        // Should only happen when this mode is active!
+        if (thread != null) {
+            thread.interrupt();
+        }
+        videoDevice.ifPresent(this::startGrabberThread);
+    }
 }