Update to 2.0.0 tree from current Fremantle build
[opencv] / src / highgui / cvcap_unicap.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2008, Xavier Delacour, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 // 2008-04-27 Xavier Delacour <xavier.delacour@gmail.com>
43
44 #include "_highgui.h"
45 #include <unistd.h>
46 #include <unicap.h>
47 extern "C" {
48 #include <ucil.h>
49 }
50
51 #ifdef NDEBUG
52 #define CV_WARN(message)
53 #else
54 #define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
55 #endif
56
57 struct CvCapture_Unicap : public CvCapture
58 {
59   CvCapture_Unicap() { init(); }
60   virtual ~CvCapture_Unicap() { close(); }
61
62   virtual bool open( int index );
63   virtual void close();
64
65   virtual double getProperty(int);
66   virtual bool setProperty(int, double);
67   virtual bool grabFrame();
68   virtual IplImage* retrieveFrame(int);
69   virtual int getCaptureDomain() { return CV_CAP_UNICAP; } // Return the type of the capture object: CV_CAP_VFW, etc...
70
71   bool shutdownDevice();
72   bool initDevice();
73
74   void init()
75   {
76     device_initialized = false;
77     desired_format = 0;
78     desired_size = cvSize(0,0);
79     convert_rgb = false;
80
81     handle = 0;
82     memset( &device, 0, sizeof(device) );
83     memset( &format_spec, 0, sizeof(format_spec) );
84     memset( &format, 0, sizeof(format) );
85     memset( &raw_buffer, 0, sizeof(raw_buffer) );
86     memset( &buffer, 0, sizeof(buffer) );
87
88     raw_frame = frame = 0;
89   }
90
91   bool device_initialized;
92
93   int desired_device;
94   int desired_format;
95   CvSize desired_size;
96   bool convert_rgb;
97
98   unicap_handle_t handle;
99   unicap_device_t device;
100   unicap_format_t format_spec;
101   unicap_format_t format;
102   unicap_data_buffer_t raw_buffer;
103   unicap_data_buffer_t buffer;
104
105   IplImage *raw_frame;
106   IplImage *frame;
107 };
108
109 bool CvCapture_Unicap::shutdownDevice() {
110   bool result = false;
111   CV_FUNCNAME("CvCapture_Unicap::shutdownDevice");
112   __BEGIN__;
113
114   if (!SUCCESS(unicap_stop_capture(handle)))
115     CV_ERROR(CV_StsError, "unicap: failed to stop capture on device\n");
116
117   if (!SUCCESS(unicap_close(handle)))
118     CV_ERROR(CV_StsError, "unicap: failed to close the device\n");
119
120   cvReleaseImage(&raw_frame);
121   cvReleaseImage(&frame);
122
123   device_initialized = false;
124
125   result = true;
126   __END__;
127   return result;
128 }
129
130 bool CvCapture_Unicap::initDevice() {
131   bool result = false;
132   CV_FUNCNAME("CvCapture_Unicap::initDevice");
133   __BEGIN__;
134
135   if (device_initialized && !shutdownDevice())
136     return false;
137
138   if(!SUCCESS(unicap_enumerate_devices(NULL, &device, desired_device)))
139     CV_ERROR(CV_StsError, "unicap: failed to get info for device\n");
140
141   if(!SUCCESS(unicap_open( &handle, &device)))
142     CV_ERROR(CV_StsError, "unicap: failed to open device\n");
143
144   unicap_void_format(&format_spec);
145
146   if (!SUCCESS(unicap_enumerate_formats(handle, &format_spec, &format, desired_format))) {
147     shutdownDevice();
148     CV_ERROR(CV_StsError, "unicap: failed to get video format\n");
149   }
150
151   int i;
152   for (i = format.size_count - 1; i > 0; i--)
153     if (format.sizes[i].width == desired_size.width &&
154         format.sizes[i].height == desired_size.height)
155       break;
156   format.size.width = format.sizes[i].width;
157   format.size.height = format.sizes[i].height;
158
159   if (!SUCCESS(unicap_set_format(handle, &format))) {
160     shutdownDevice();
161     CV_ERROR(CV_StsError, "unicap: failed to set video format\n");
162   }
163
164   memset(&raw_buffer, 0x0, sizeof(unicap_data_buffer_t));
165   raw_frame = cvCreateImage(cvSize(format.size.width,
166                                         format.size.height),
167                                   8, format.bpp / 8);
168   memcpy(&raw_buffer.format, &format, sizeof(raw_buffer.format));
169   raw_buffer.data = (unsigned char*)raw_frame->imageData;
170   raw_buffer.buffer_size = format.size.width *
171     format.size.height * format.bpp / 8;
172
173   memset(&buffer, 0x0, sizeof(unicap_data_buffer_t));
174   memcpy(&buffer.format, &format, sizeof(buffer.format));
175
176   buffer.format.fourcc = UCIL_FOURCC('B','G','R','3');
177   buffer.format.bpp = 24;
178   // * todo support greyscale output
179   //    buffer.format.fourcc = UCIL_FOURCC('G','R','E','Y');
180   //    buffer.format.bpp = 8;
181
182   frame = cvCreateImage(cvSize(buffer.format.size.width,
183                                     buffer.format.size.height),
184                               8, buffer.format.bpp / 8);
185   buffer.data = (unsigned char*)frame->imageData;
186   buffer.buffer_size = buffer.format.size.width *
187     buffer.format.size.height * buffer.format.bpp / 8;
188
189   if(!SUCCESS(unicap_start_capture(handle))) {
190     shutdownDevice();
191     CV_ERROR(CV_StsError, "unicap: failed to start capture on device\n");
192   }
193
194   device_initialized = true;
195   result = true;
196   __END__;
197   return result;
198 }
199
200 void CvCapture_Unicap::close() {
201   if(device_initialized)
202     shutdownDevice();
203 }
204
205 bool CvCapture_Unicap::grabFrame() {
206   bool result = false;
207
208   CV_FUNCNAME("CvCapture_Unicap::grabFrame");
209   __BEGIN__;
210
211   unicap_data_buffer_t *returned_buffer;
212
213   int retry_count = 100;
214
215   while (retry_count--) {
216     if(!SUCCESS(unicap_queue_buffer(handle, &raw_buffer)))
217       CV_ERROR(CV_StsError, "unicap: failed to queue a buffer on device\n");
218
219     if(SUCCESS(unicap_wait_buffer(handle, &returned_buffer)))
220     {
221       result = true;
222       EXIT;
223     }
224
225     CV_WARN("unicap: failed to wait for buffer on device\n");
226     usleep(100 * 1000);
227   }
228
229   __END__;
230   return result;
231 }
232
233 IplImage * CvCapture_Unicap::retrieveFrame(int) {
234   if (convert_rgb) {
235     ucil_convert_buffer(&buffer, &raw_buffer);
236     return frame;
237   }
238   return raw_frame;
239 }
240
241 double CvCapture_Unicap::getProperty(int id) {
242   switch (id) {
243   case CV_CAP_PROP_POS_MSEC: break;
244   case CV_CAP_PROP_POS_FRAMES: break;
245   case CV_CAP_PROP_POS_AVI_RATIO: break;
246   case CV_CAP_PROP_FRAME_WIDTH:
247     return desired_size.width;
248   case CV_CAP_PROP_FRAME_HEIGHT:
249     return desired_size.height;
250   case CV_CAP_PROP_FPS: break;
251   case CV_CAP_PROP_FOURCC: break;
252   case CV_CAP_PROP_FRAME_COUNT: break;
253   case CV_CAP_PROP_FORMAT:
254     return desired_format;
255   case CV_CAP_PROP_MODE: break;
256   case CV_CAP_PROP_BRIGHTNESS: break;
257   case CV_CAP_PROP_CONTRAST: break;
258   case CV_CAP_PROP_SATURATION: break;
259   case CV_CAP_PROP_HUE: break;
260   case CV_CAP_PROP_GAIN: break;
261   case CV_CAP_PROP_CONVERT_RGB:
262     return convert_rgb;
263   }
264
265   return 0;
266 }
267
268 bool CvCapture_Unicap::setProperty(int id, double value) {
269   bool reinit = false;
270
271   switch (id) {
272   case CV_CAP_PROP_POS_MSEC: break;
273   case CV_CAP_PROP_POS_FRAMES: break;
274   case CV_CAP_PROP_POS_AVI_RATIO: break;
275   case CV_CAP_PROP_FRAME_WIDTH:
276     desired_size.width = (int)value;
277     reinit = true;
278     break;
279   case CV_CAP_PROP_FRAME_HEIGHT:
280     desired_size.height = (int)value;
281     reinit = true;
282     break;
283   case CV_CAP_PROP_FPS: break;
284   case CV_CAP_PROP_FOURCC: break;
285   case CV_CAP_PROP_FRAME_COUNT: break;
286   case CV_CAP_PROP_FORMAT:
287     desired_format = id;
288     reinit = true;
289     break;
290   case CV_CAP_PROP_MODE: break;
291   case CV_CAP_PROP_BRIGHTNESS: break;
292   case CV_CAP_PROP_CONTRAST: break;
293   case CV_CAP_PROP_SATURATION: break;
294   case CV_CAP_PROP_HUE: break;
295   case CV_CAP_PROP_GAIN: break;
296   case CV_CAP_PROP_CONVERT_RGB:
297     convert_rgb = value != 0;
298     break;
299   }
300
301   if (reinit && !initDevice())
302     return false;
303
304   return true;
305 }
306
307 bool CvCapture_Unicap::open(int index)
308 {
309   close();
310   device_initialized = false;
311
312   desired_device = index < 0 ? 0 : index;
313   desired_format = 0;
314   desired_size = cvSize(320, 240);
315   convert_rgb = true;
316
317   return initDevice();
318 }
319
320
321 CvCapture * cvCreateCameraCapture_Unicap(const int index)
322 {
323   CvCapture_Unicap *cap = new CvCapture_Unicap;
324   if( cap->open(index) )
325     return cap;
326   delete cap;
327   return 0;
328 }