Merge branch 'master' of ssh://dolda2000.com/srv/git/r/kaka/cakelight
[kaka/cakelight.git] / src / kaka / cakelight / mode / VideoMode.java
1 package kaka.cakelight.mode;
2
3 import kaka.cakelight.Configuration;
4 import kaka.cakelight.FrameGrabber;
5 import kaka.cakelight.VideoDeviceListener;
6 import kaka.cakelight.VideoFrame;
7
8 import java.io.File;
9 import java.io.IOException;
10 import java.util.Optional;
11 import java.util.function.Consumer;
12
13 public class VideoMode extends Mode {
14     private Configuration config;
15     private Thread grabberThread;
16     private Consumer<VideoFrame> frameConsumer;
17     private VideoDeviceListener deviceListener;
18     private boolean isPaused = false;
19
20     public VideoMode() {
21         deviceListener = new VideoDeviceListener();
22         deviceListener.onVideoDeviceChange(this::onVideoDeviceChange);
23     }
24
25     @Override
26     public void enter(Configuration config) {
27         this.config = config;
28         if (config.video.deviceIsAutomatic) {
29             deviceListener.startListening();
30         } else {
31             File videoDevice = new File(config.video.device);
32             startGrabberThread(videoDevice);
33         }
34     }
35
36     @Override
37     public void pause() {
38         isPaused = true;
39     }
40
41     @Override
42     public void resume() {
43         isPaused = false;
44         synchronized (grabberThread) {
45             grabberThread.notify();
46         }
47     }
48
49     @Override
50     public void exit() {
51         grabberThread.interrupt();
52         if (config.video.deviceIsAutomatic) {
53             deviceListener.stopListening();
54         }
55     }
56
57     private void startGrabberThread(File videoDevice) {
58         assert frameConsumer != null;
59         grabberThread = new Thread() {
60             public void run() {
61                 try (FrameGrabber grabber = FrameGrabber.from(videoDevice, config)) {
62                     while (!isInterrupted()) {
63                         Optional<VideoFrame> frame = grabber.grabFrame();
64                         if (isPaused) {
65                             synchronized (grabberThread) {
66                                 wait();
67                             }
68                         }
69                         if (frameConsumer != null) frame.ifPresent(frameConsumer);
70                         frame.ifPresent(VideoMode.this::onVideoFrame);
71 //                        timeIt("frame", grabber::grabFrame);
72                     }
73                 } catch (IOException | InterruptedException e) {
74                     e.printStackTrace();
75                 }
76             }
77         };
78         grabberThread.start();
79     }
80
81     public void onVideoFrame(Consumer<VideoFrame> consumer) {
82         frameConsumer = consumer;
83     }
84
85     private void onVideoFrame(VideoFrame frame) {
86         updateWithFrame(frame.getLedFrame());
87     }
88
89     public void onVideoDeviceChange(Optional<File> videoDevice) {
90         // Should only happen when this mode is active!
91         if (grabberThread != null) {
92             grabberThread.interrupt();
93         }
94         videoDevice.ifPresent(this::startGrabberThread);
95     }
96 }