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 "precomp.hpp"
45#include <unistd.h>
46#include <unicap.h>
47extern "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
57struct 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) const;
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
109bool 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
130bool 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  if (format.sizes)
153  {
154      for (i = format.size_count - 1; i > 0; i--)
155        if (format.sizes[i].width == desired_size.width &&
156        format.sizes[i].height == desired_size.height)
157          break;
158      format.size.width = format.sizes[i].width;
159      format.size.height = format.sizes[i].height;
160  }
161
162  if (!SUCCESS(unicap_set_format(handle, &format))) {
163    shutdownDevice();
164    CV_ERROR(CV_StsError, "unicap: failed to set video format\n");
165  }
166
167  memset(&raw_buffer, 0x0, sizeof(unicap_data_buffer_t));
168  raw_frame = cvCreateImage(cvSize(format.size.width,
169                    format.size.height),
170                  8, format.bpp / 8);
171  memcpy(&raw_buffer.format, &format, sizeof(raw_buffer.format));
172  raw_buffer.data = (unsigned char*)raw_frame->imageData;
173  raw_buffer.buffer_size = format.size.width *
174    format.size.height * format.bpp / 8;
175
176  memset(&buffer, 0x0, sizeof(unicap_data_buffer_t));
177  memcpy(&buffer.format, &format, sizeof(buffer.format));
178
179  buffer.format.fourcc = UCIL_FOURCC('B','G','R','3');
180  buffer.format.bpp = 24;
181  // * todo support greyscale output
182  //    buffer.format.fourcc = UCIL_FOURCC('G','R','E','Y');
183  //    buffer.format.bpp = 8;
184
185  frame = cvCreateImage(cvSize(buffer.format.size.width,
186                    buffer.format.size.height),
187                  8, buffer.format.bpp / 8);
188  buffer.data = (unsigned char*)frame->imageData;
189  buffer.buffer_size = buffer.format.size.width *
190    buffer.format.size.height * buffer.format.bpp / 8;
191
192  if(!SUCCESS(unicap_start_capture(handle))) {
193    shutdownDevice();
194    CV_ERROR(CV_StsError, "unicap: failed to start capture on device\n");
195  }
196
197  device_initialized = true;
198  result = true;
199  __END__;
200  return result;
201}
202
203void CvCapture_Unicap::close() {
204  if(device_initialized)
205    shutdownDevice();
206}
207
208bool CvCapture_Unicap::grabFrame() {
209  bool result = false;
210
211  CV_FUNCNAME("CvCapture_Unicap::grabFrame");
212  __BEGIN__;
213
214  unicap_data_buffer_t *returned_buffer;
215
216  int retry_count = 100;
217
218  while (retry_count--) {
219    if(!SUCCESS(unicap_queue_buffer(handle, &raw_buffer)))
220      CV_ERROR(CV_StsError, "unicap: failed to queue a buffer on device\n");
221
222    if(SUCCESS(unicap_wait_buffer(handle, &returned_buffer)))
223    {
224      result = true;
225      EXIT;
226    }
227
228    CV_WARN("unicap: failed to wait for buffer on device\n");
229    usleep(100 * 1000);
230  }
231
232  __END__;
233  return result;
234}
235
236IplImage * CvCapture_Unicap::retrieveFrame(int) {
237  if (convert_rgb) {
238    ucil_convert_buffer(&buffer, &raw_buffer);
239    return frame;
240  }
241  return raw_frame;
242}
243
244double CvCapture_Unicap::getProperty(int id) const
245{
246  switch (id) {
247  case CV_CAP_PROP_POS_MSEC: break;
248  case CV_CAP_PROP_POS_FRAMES: break;
249  case CV_CAP_PROP_POS_AVI_RATIO: break;
250  case CV_CAP_PROP_FRAME_WIDTH:
251    return desired_size.width;
252  case CV_CAP_PROP_FRAME_HEIGHT:
253    return desired_size.height;
254  case CV_CAP_PROP_FPS: break;
255  case CV_CAP_PROP_FOURCC: break;
256  case CV_CAP_PROP_FRAME_COUNT: break;
257  case CV_CAP_PROP_FORMAT:
258    return desired_format;
259  case CV_CAP_PROP_MODE: break;
260  case CV_CAP_PROP_BRIGHTNESS: break;
261  case CV_CAP_PROP_CONTRAST: break;
262  case CV_CAP_PROP_SATURATION: break;
263  case CV_CAP_PROP_HUE: break;
264  case CV_CAP_PROP_GAIN: break;
265  case CV_CAP_PROP_CONVERT_RGB:
266    return convert_rgb;
267  }
268
269  return 0;
270}
271
272bool CvCapture_Unicap::setProperty(int id, double value) {
273  bool reinit = false;
274
275  switch (id) {
276  case CV_CAP_PROP_POS_MSEC: break;
277  case CV_CAP_PROP_POS_FRAMES: break;
278  case CV_CAP_PROP_POS_AVI_RATIO: break;
279  case CV_CAP_PROP_FRAME_WIDTH:
280    desired_size.width = (int)value;
281    reinit = true;
282    break;
283  case CV_CAP_PROP_FRAME_HEIGHT:
284    desired_size.height = (int)value;
285    reinit = true;
286    break;
287  case CV_CAP_PROP_FPS: break;
288  case CV_CAP_PROP_FOURCC: break;
289  case CV_CAP_PROP_FRAME_COUNT: break;
290  case CV_CAP_PROP_FORMAT:
291    desired_format = id;
292    reinit = true;
293    break;
294  case CV_CAP_PROP_MODE: break;
295  case CV_CAP_PROP_BRIGHTNESS: break;
296  case CV_CAP_PROP_CONTRAST: break;
297  case CV_CAP_PROP_SATURATION: break;
298  case CV_CAP_PROP_HUE: break;
299  case CV_CAP_PROP_GAIN: break;
300  case CV_CAP_PROP_CONVERT_RGB:
301    convert_rgb = value != 0;
302    break;
303  }
304
305  if (reinit && !initDevice())
306    return false;
307
308  return true;
309}
310
311bool CvCapture_Unicap::open(int index)
312{
313  close();
314  device_initialized = false;
315
316  desired_device = index < 0 ? 0 : index;
317  desired_format = 0;
318  desired_size = cvSize(320, 240);
319  convert_rgb = true;
320
321  return initDevice();
322}
323
324
325CvCapture * cvCreateCameraCapture_Unicap(const int index)
326{
327  CvCapture_Unicap *cap = new CvCapture_Unicap;
328  if( cap->open(index) )
329    return cap;
330  delete cap;
331  return 0;
332}
333