Project

General

Profile

BitmapToolkit Scol plugin
CameraInput.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24
25#include "CameraInput.h"
26
27#ifdef _WIN32
28#include <dshow.h>
29#endif
30
31std::list<CameraInput*> CameraInput::cameraInputsList;
32
33#ifdef ANDROID
34static cv::Size calc_optimal_camera_resolution(const char* supported, int width, int height)
35{
36 int frame_width = 0;
37 int frame_height = 0;
38
39 size_t prev_idx = 0;
40 size_t idx = 0;
41 float min_diff = FLT_MAX;
42
43 do
44 {
45 int tmp_width;
46 int tmp_height;
47
48 prev_idx = idx;
49 while ((supported[idx] != '\0') && (supported[idx] != ','))
50 idx++;
51
52 sscanf(&supported[prev_idx], "%dx%d", &tmp_width, &tmp_height);
53
54 int w_diff = width - tmp_width;
55 int h_diff = height - tmp_height;
56 if ((h_diff >= 0) && (w_diff >= 0))
57 {
58 if ((h_diff <= min_diff) && (tmp_height <= 720))
59 {
60 frame_width = tmp_width;
61 frame_height = tmp_height;
62 min_diff = h_diff;
63 }
64 }
65
66 idx++; // to skip comma symbol
67
68 } while (supported[idx - 1] != '\0');
69
70 return cv::Size(frame_width, frame_height);
71}
72#endif
73
75{
76#ifdef _WIN32
77 mVI = new videoInput();
78#else
79 mVI = new cv::VideoCapture();
80#endif
81
82 mIndex = index;
83 mMirrorMode = false;
84 cameraInputsList.push_back(this);
85 mBufferSize = cv::Size(640, 480);
86}
87
89{
90 bool ret = false;
91
92#ifdef _WIN32
93 ret = mVI->setupDevice(mIndex); // crash when problem occured
94 if (!ret)
95 ret = mVI->setupDevice(mIndex, VI_COMPOSITE); // crash when problem occured
96
97 if (ret)
98 mBuffer.resize(mVI->getSize(mIndex));
99
100#elif ANDROID
101 if (mIndex == 0)
102 mIndex = CV_CAP_ANDROID_BACK;
103 else if (mIndex == 1)
104 mIndex = CV_CAP_ANDROID_FRONT;
105
106 ret = mVI->open(mIndex);
107
108 // init default size (Pass the webcam in preview mode !!)
109
110 mVI->set(CV_CAP_PROP_ANDROID_ANTIBANDING, CV_CAP_ANDROID_ANTIBANDING_OFF);
111 mVI->set(CV_CAP_PROP_ANDROID_FOCUS_MODE, CV_CAP_ANDROID_FOCUS_MODE_CONTINUOUS_VIDEO);
112 //mVI->set(CV_CAP_PROP_ANDROID_FLASH_MODE, CV_CAP_ANDROID_FLASH_MODE_TORCH);
113
114 SetSize(mBufferSize.width, mBufferSize.height);
115
116#else
117 ret = mVI->open(mIndex);
118#endif
119
120 return ret;
121}
122
124{
125#ifdef _WIN32
126 mVI->stopDevice(mIndex);
127#else
128 mVI->release();
129#endif
130}
131
133{
134#ifdef _WIN32
135 mVI->stopDevice(mIndex);
136#else
137 mVI->release();
138#endif
139
140 cameraInputsList.remove(this);
141 SAFE_DELETE(mVI);
142}
143
145{
146#ifdef _WIN32
147 return mVI->isDeviceSetup(mIndex);
148#else
149 return mVI->isOpened();
150#endif
151}
152
154{
155 if (!IsOpened())
156 throw std::logic_error("Device not initialised");
157
158#ifdef _WIN32
159 // Capture the picture
160 if (!mVI->isFrameNew(mIndex) || !mVI->getPixels(mIndex, &mBuffer[0], false, true))
161 {
162 throw std::logic_error("Device has bad pixel buffer");
163 }
164
165 cv::Mat frame(mVI->getHeight(mIndex), mVI->getWidth(mIndex), CV_8UC3, &mBuffer[0]);
166
167 //if (mMirrorMode) cv::flip(frame,frame,1);
168 return frame;
169#else
170 if (!mVI->grab())
171 throw std::logic_error("Device has bad pixel buffer");
172
173 cv::Mat frame;
174 if (!mVI->retrieve(frame, CV_CAP_ANDROID_COLOR_FRAME_BGR) || frame.empty())
175 throw std::logic_error("frame is empty");
176
177 return frame;
178#endif
179}
180
182{
183 if (IsOpened())
184 {
185#ifdef _WIN32
186 return mVI->getWidth(mIndex);
187#else
188 return mBufferSize.width;//mVI->get(CV_CAP_PROP_FRAME_WIDTH);
189#endif
190 }
191 else
192 return 0;
193}
194
196{
197 if (IsOpened())
198 {
199#ifdef _WIN32
200 return mVI->getHeight(mIndex);
201#else
202 return mBufferSize.height;//mVI->get(CV_CAP_PROP_FRAME_HEIGHT);
203#endif
204 }
205 else
206 return 0;
207}
208
209void CameraInput::SetSize(int width, int height)
210{
211 if (IsOpened())
212 {
213#ifdef _WIN32
214 mVI->stopDevice(mIndex);
215 mVI->setupDevice(mIndex, width, height);
216
217 //if the size is not supported we restart with the default size
218 if (!IsOpened())
219 mVI->setupDevice(mIndex);
220
221 mBuffer.resize(mVI->getSize(mIndex));
222#else
223 union { double prop; const char* name; } u;
224 u.prop = mVI->get(CV_CAP_PROP_SUPPORTED_PREVIEW_SIZES_STRING);
225
226 mBufferSize = cv::Size(0, 0);
227 if (u.name)
228 {
229 mBufferSize = calc_optimal_camera_resolution(u.name, width, height);
230 }
231 else
232 {
233 MMechostr(MSKRUNTIME, ">> Cannot get supported camera camera_resolutions\n");
234 }
235
236 MMechostr(MSKDEBUG, ">>>> Camera set size : %ix%i\n", mBufferSize.width, mBufferSize.height);
237
238 if ((mBufferSize.width != 0) && (mBufferSize.height != 0))
239 {
240 mVI->set(CV_CAP_PROP_FRAME_WIDTH, mBufferSize.width);
241 mVI->set(CV_CAP_PROP_FRAME_HEIGHT, mBufferSize.height);
242 }
243 else
244 {
245 mBufferSize = cv::Size(640, 480);
246 }
247#endif
248 }
249}
250
252{
253 return mMirrorMode;
254}
255
257{
258 mMirrorMode = mode;
259}
260
261std::vector<std::string> CameraInput::GetDevicesList()
262{
263 std::vector<std::string> result;
264
265#ifdef _WIN32
266 IBaseFilter *p_base_filter = NULL;
267 IMoniker *p_moniker = NULL;
268 ULONG i_fetched;
269 HRESULT hr;
270
271 /*Create the system device enumerator*/
272 ICreateDevEnum *p_dev_enum = NULL;
273
274 hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&p_dev_enum);
275
276 if (FAILED(hr))
277 {
278 return result;
279 }
280
281 /* Create an enumerator for the video capture devices */
282 IEnumMoniker *p_class_enum = NULL;
283 hr = p_dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &p_class_enum, 0);
284
285 p_dev_enum->Release();
286 if (FAILED(hr))
287 {
288 return result;
289 }
290
291 /* If there are no enumerators for the requested type, then
292 * CreateClassEnumerator will succeed, but p_class_enum will be NULL */
293 if (p_class_enum == NULL)
294 {
295 return result;
296 }
297
298 /* Enumerate the devices */
299
300 /* Note that if the Next() call succeeds but there are no monikers,
301 * it will return S_FALSE (which is not a failure). Therefore, we check
302 * that the return code is S_OK instead of using SUCCEEDED() macro. */
303
304 int n = 0;
305
306 while (p_class_enum->Next(1, &p_moniker, &i_fetched) == S_OK)
307 {
308 /* Getting the property page to get the device name */
309 IPropertyBag *p_bag;
310 hr = p_moniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&p_bag);
311 if (SUCCEEDED(hr))
312 {
313 VARIANT var;
314 var.vt = VT_BSTR;
315 hr = p_bag->Read(L"FriendlyName", &var, NULL);
316 p_bag->Release();
317
318 if (SUCCEEDED(hr))
319 {
320 int i_convert = WideCharToMultiByte(CP_ACP, 0, var.bstrVal, SysStringLen(var.bstrVal), NULL, 0, NULL, NULL);
321 char *p_buf = (char *)malloc(i_convert + 1);
322 p_buf[0] = 0;
323
324 WideCharToMultiByte(CP_ACP, 0, var.bstrVal, SysStringLen(var.bstrVal), p_buf, i_convert, NULL, NULL);
325 SysFreeString(var.bstrVal);
326 p_buf[i_convert] = '\0';
327
328 result.push_back(std::string(p_buf));
329
330 free(p_buf);
331 n++;
332 }
333 }
334 p_moniker->Release();
335 }
336
337 p_class_enum->Release();
338
339#else // unix, android ...
340
341 unsigned int cameraNumber = 0; // number of cameras detected
342 cv::VideoCapture temp_camera;
343
344 for (int i = 0; i < 128; i++)
345 {
346 cv::VideoCapture temp_camera(i);
347 if (temp_camera.isOpened())
348 {
349 char buffer[6];
350 sprintf(buffer, "cam%d", cameraNumber);
351 result.push_back(buffer);
352 cameraNumber++;
353 }
354 else if (temp_camera.open(i))
355 {
356 char buffer[6];
357 sprintf(buffer, "cam%d", cameraNumber);
358 result.push_back(buffer);
359 cameraNumber++;
360 temp_camera.release();
361 }
362 else
363 break;
364 }
365
366#endif
367
368 return result;
369}
370
371bool CameraInput::TakeSnapshot(std::string path)
372{
373 std::cout << "taking a snapshot of camera" << mIndex << "... ";
374 if (!IsOpened())
375 {
376 std::cout << "failed. camera not opened yet." << std::endl;
377 return false;
378 }
379
380 cv::Mat frame = UpdateImage();
381 if (frame.empty())
382 {
383 std::cout << "failed. Frame is empty." << std::endl;
384 return false;
385 }
386
387 if (!cv::imwrite(path, frame))
388 {
389 std::cout << "failed. Couldn't write to " << path << "." << std::endl;
390 return false;
391 }
392
393 std::cout << "success. Frame written to " << path << "." << std::endl;
394 return true;
395}
396
397#ifndef ANDROID
399#else
401{
402 cv::Mat frame;
403 try
404 {
405 MMechostr(MSKDEBUG, ">>>> updating frame");
406 frame = UpdateImage();
407 }
408 catch (std::exception e)
409 {
410 MMechostr(MSKDEBUG, ">>>> %s", e.what());
411 return;
412 }
413
414 if (frame.empty())
415 {
416 MMechostr(MSKDEBUG, ">>>> frame empty!");
417 return;
418 }
419
420 ANativeWindow* window = (ANativeWindow*)SCgetExtra("hscol");
421 if (!window)
422 {
423 MMechostr(MSKDEBUG, "error: window empty !");
424 return;
425 }
426 ANativeWindow_Buffer buffer;
427
428 // Try lock buffer
429 if (ANativeWindow_lock(window, &buffer, 0) < 0)
430 return;
431
432 //MMechostr(MSKDEBUG, "buffer info :: width = %d height = %d stride = %d format = %d", buffer.width, buffer.height, buffer.stride, buffer.format);
433
434 cv::resize(frame, frame, cv::Size(buffer.width, buffer.height), 0, 0, cv::INTER_CUBIC);
435
436 for (unsigned int y = 0; y < frame.rows; y++)
437 {
438 for (unsigned int x = 0; x < frame.cols; x++)
439 {
440 unsigned long srcByte = (x * 3) + (frame.cols * 3 * y);
441 unsigned long destByte = (x * 4) + (buffer.width * 4 * y);
442
443 ((unsigned char*)buffer.bits)[destByte + 2] = frame.data[srcByte];
444 ((unsigned char*)buffer.bits)[destByte + 1] = frame.data[srcByte + 1];
445 ((unsigned char*)buffer.bits)[destByte + 0] = frame.data[srcByte + 2];
446 ((unsigned char*)buffer.bits)[destByte + 3] = 255;
447 }
448 }
449
450 // Unlock buffer
451 ANativeWindow_unlockAndPost(window);
452}
453#endif
454
456{
457 std::list<CameraInput*>::iterator it;
458 if (state)
459 {
460 for(it = cameraInputsList.begin(); it != cameraInputsList.end(); it++)
461 {
462 (*it)->Initialize();
463 }
464 }
465 else
466 {
467 for(it = cameraInputsList.begin(); it != cameraInputsList.end(); it++)
468 {
469 (*it)->Close();
470 }
471 }
472}
static std::vector< std::string > GetDevicesList()
cv::Mat UpdateImage()
void SetSize(int width, int height)
void SetMirrorMode(bool mode)
static std::list< CameraInput * > cameraInputsList
Definition CameraInput.h:45
static void SetCameraInputsState(bool state)
CameraInput(int index)
bool GetMirrorMode()
bool TakeSnapshot(std::string path)
void RenderToScreen()
bool Initialize()