001 package com.github.sarxos.webcam.ds.civil;
002
003 import java.awt.Dimension;
004 import java.awt.image.BufferedImage;
005 import java.util.ArrayList;
006 import java.util.Collections;
007 import java.util.Comparator;
008 import java.util.HashSet;
009 import java.util.List;
010 import java.util.Set;
011
012 import org.slf4j.Logger;
013 import org.slf4j.LoggerFactory;
014
015 import com.github.sarxos.webcam.WebcamDevice;
016 import com.lti.civil.CaptureDeviceInfo;
017 import com.lti.civil.CaptureException;
018 import com.lti.civil.CaptureObserver;
019 import com.lti.civil.CaptureStream;
020 import com.lti.civil.CaptureSystem;
021 import com.lti.civil.Image;
022 import com.lti.civil.VideoFormat;
023 import com.lti.civil.awt.AWTImageConverter;
024
025
026 /**
027 * Webcam device - LTI-CIVIL framework compatible implementation.
028 *
029 * @author Bartosz Firyn (SarXos)
030 */
031 public class LtiCivilDevice implements WebcamDevice, CaptureObserver {
032
033 private static final Logger LOG = LoggerFactory.getLogger(LtiCivilDevice.class);
034
035 private CaptureDeviceInfo cdi = null;
036 private List<Dimension> dimensions = null;
037 private Dimension size = null;
038 private Image image = null;
039 private CaptureStream stream = null;
040
041 private volatile boolean open = false;
042 private volatile boolean capturing = false;
043 private volatile boolean disposed = false;
044
045 protected LtiCivilDevice(CaptureDeviceInfo cdi) {
046 this.cdi = cdi;
047 }
048
049 @Override
050 public String getName() {
051 return cdi.getDescription();
052 }
053
054 @Override
055 public Dimension[] getResolutions() {
056
057 if (dimensions == null) {
058 dimensions = new ArrayList<Dimension>();
059
060 CaptureSystem system = LtiCivilDriver.getCaptureSystem();
061 Set<Dimension> set = new HashSet<Dimension>();
062
063 try {
064
065 stream = system.openCaptureDeviceStream(cdi.getDeviceID());
066
067 for (VideoFormat format : stream.enumVideoFormats()) {
068 if (format.getFormatType() == VideoFormat.RGB24) {
069 set.add(new Dimension(format.getWidth(), format.getHeight()));
070 }
071 }
072
073 stream.dispose();
074
075 } catch (CaptureException e) {
076 LOG.error("Capture exception when collecting formats dimension", e);
077 }
078
079 dimensions.addAll(set);
080
081 Collections.sort(dimensions, new Comparator<Dimension>() {
082
083 @Override
084 public int compare(Dimension a, Dimension b) {
085 int apx = a.width * a.height;
086 int bpx = b.width * b.height;
087 if (apx > bpx) {
088 return 1;
089 } else if (apx < bpx) {
090 return -1;
091 } else {
092 return 0;
093 }
094 }
095 });
096 }
097
098 return dimensions.toArray(new Dimension[dimensions.size()]);
099 }
100
101 @Override
102 public BufferedImage getImage() {
103 if (!capturing) {
104 return null;
105 }
106 return AWTImageConverter.toBufferedImage(image);
107 }
108
109 @Override
110 public void onError(CaptureStream stream, CaptureException e) {
111 LOG.error("Exception in capture stream", e);
112 }
113
114 @Override
115 public void onNewImage(CaptureStream stream, Image image) {
116 this.image = image;
117 this.capturing = true;
118 }
119
120 @Override
121 public void open() {
122
123 if (open || disposed) {
124 return;
125 }
126
127 try {
128 stream = LtiCivilDriver.getCaptureSystem().openCaptureDeviceStream(cdi.getDeviceID());
129 stream.setVideoFormat(findFormat());
130 stream.setObserver(this);
131 stream.start();
132 } catch (CaptureException e) {
133 LOG.error("Capture exception when opening Civil device", e);
134 }
135 while (true) {
136 if (capturing) {
137 break;
138 }
139 try {
140 Thread.sleep(100);
141 } catch (InterruptedException e) {
142 }
143 }
144 }
145
146 private VideoFormat findFormat() {
147 if (stream == null) {
148 throw new RuntimeException("Stream is null");
149 }
150 if (size == null) {
151 throw new RuntimeException("Size is not set");
152 }
153 try {
154 for (VideoFormat format : stream.enumVideoFormats()) {
155 if (format.getFormatType() == VideoFormat.RGB24) {
156 boolean xok = size.width == format.getWidth();
157 boolean yok = size.height == format.getHeight();
158 if (xok && yok) {
159 return format;
160 }
161 }
162 }
163 } catch (CaptureException e) {
164 LOG.error("Capture exception when iterating thru video formats", e);
165 }
166 throw new RuntimeException("Cannot find RGB24 video format for size [" + size.width + "x" + size.height + "]");
167 }
168
169 @Override
170 public void close() {
171 if (!open) {
172 return;
173 }
174 try {
175 stream.stop();
176 stream.dispose();
177 } catch (CaptureException e) {
178 LOG.error("Capture exception when closing Civil device", e);
179 }
180 }
181
182 @Override
183 public Dimension getResolution() {
184 return size;
185 }
186
187 @Override
188 public void setResolution(Dimension d) {
189 this.size = d;
190 }
191
192 @Override
193 public void dispose() {
194 disposed = true;
195 }
196
197 @Override
198 public boolean isOpen() {
199 return open;
200 }
201 }