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