source: BAORadio/libindi/v1/libs/webcam/v4l1_base.cpp@ 689

Last change on this file since 689 was 490, checked in by campagne, 15 years ago

import libindi (JEC)

File size: 12.1 KB
Line 
1/*
2 Copyright (C) 2005 by Jasem Mutlaq
3 Email: mutlaqja@ikarustech.com
4
5 Some code based on qastrocam
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
21*/
22
23#include <iostream>
24
25#include <sys/ioctl.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <unistd.h>
30#include <stdio.h>
31#include <errno.h>
32#include <sys/mman.h>
33#include <string.h>
34
35#include "ccvt.h"
36#include "v4l1_base.h"
37#include "eventloop.h"
38#include "indidevapi.h"
39
40#define ERRMSGSIZ 1024
41
42using namespace std;
43
44V4L1_Base::V4L1_Base()
45{
46 frameRate=10;
47 fd=-1;
48 //usingTimer = false;
49
50 //frameUpdate = true;
51 //selectCallBackID = -1;
52 //timerCallBackID = -1;
53
54 YBuf = NULL;
55 UBuf = NULL;
56 VBuf = NULL;
57 colorBuffer= NULL;
58 buffer_start=NULL;
59
60}
61
62V4L1_Base::~V4L1_Base()
63{
64
65 delete (YBuf);
66 delete (UBuf);
67 delete (VBuf);
68 delete (colorBuffer);
69
70}
71
72int V4L1_Base::connectCam(const char * devpath, char *errmsg)
73{
74 options= (haveBrightness|haveContrast|haveHue|haveColor|haveWhiteness);
75
76 buffer_start=NULL;
77 frameRate=10;
78 fd=-1;
79
80 //cerr << "In connect Cam with device " << devpath << endl;
81 if (-1 == (fd=open(devpath, O_RDWR | O_NONBLOCK, 0)))
82 {
83 if (-1 == (fd=open(devpath, O_RDONLY | O_NONBLOCK, 0)))
84 {
85 strncpy(errmsg, strerror(errno), ERRMSGSIZ);
86 cerr << strerror(errno);
87 return -1;
88 }
89 }
90
91 cerr << "Device opened" << endl;
92
93 if (fd != -1)
94 {
95 if (-1 == ioctl(fd,VIDIOCGCAP,&capability))
96 {
97 cerr << "Error: ioctl (VIDIOCGCAP)" << endl;
98 strncpy(errmsg, "ioctl (VIDIOCGCAP)", ERRMSGSIZ);
99 return -1;
100 }
101 if (-1 == ioctl (fd, VIDIOCGWIN, &window))
102 {
103 cerr << "Error ioctl (VIDIOCGWIN)" << endl;
104 strncpy(errmsg, "ioctl (VIDIOCGWIN)", ERRMSGSIZ);
105 return -1;
106 }
107 if (-1 == ioctl (fd, VIDIOCGPICT, &picture_format))
108 {
109 cerr << "Error: ioctl (VIDIOCGPICT)" << endl;
110 strncpy(errmsg, "ioctl (VIDIOCGPICT)", ERRMSGSIZ);
111 return -1;
112 }
113
114 init(0);
115 }
116
117 cerr << "initial size w:" << window.width << " -- h: " << window.height << endl;
118
119 /*if (options & ioUseSelect)
120 {
121 selectCallBackID = addCallback(fd, V4L1_Base::staticUpdateFrame, this);
122 cerr << "Using select to wait new frames." << endl;
123 } else
124 {
125 usingTimer = true;
126 timerCallBackID = addTimer(1000/frameRate, V4L1_Base::staticCallFrame, this);
127 cerr << "Using timer to wait new frames.\n";
128 }
129 */
130
131 if (mmapInit() < 0)
132 {
133 strncpy(errmsg, "mmapInit() failed", ERRMSGSIZ);
134 return -1;
135 }
136
137 cerr << "All successful, returning\n";
138 return fd;
139}
140
141void V4L1_Base::disconnectCam()
142{
143
144
145 delete YBuf;
146 delete UBuf;
147 delete VBuf;
148 YBuf = UBuf = VBuf = NULL;
149
150 if (selectCallBackID != -1)
151 rmCallback(selectCallBackID);
152
153 //if (usingTimer && timerCallBackID != -1)
154 //rmTimer(timerCallBackID);
155
156 if (munmap (buffer_start, mmap_buffer.size) < 0)
157 fprintf(stderr, "munmap: %s\n", strerror(errno));
158
159 if (close(fd) < 0)
160 fprintf(stderr, "close(fd): %s\n", strerror(errno));
161
162 fprintf(stderr, "Disconnect cam\n");
163}
164
165void V4L1_Base::newFrame()
166{
167 switch (picture_format.palette)
168 {
169 case VIDEO_PALETTE_GREY:
170 memcpy(YBuf,mmapFrame(),window.width * window.height);
171 break;
172 case VIDEO_PALETTE_YUV420P:
173 memcpy(YBuf,mmapFrame(), window.width * window.height);
174 memcpy(UBuf,
175 mmapFrame()+ window.width * window.height,
176 (window.width/2) * (window.height/2));
177 memcpy(VBuf,
178 mmapFrame()+ window.width * window.height+(window.width/2) * (window.height/2),
179 (window.width/2) * (window.height/2));
180 break;
181 case VIDEO_PALETTE_YUYV:
182 ccvt_yuyv_420p(window.width,window.height,
183 mmapFrame(),
184 YBuf,
185 UBuf,
186 VBuf);
187 break;
188
189 case VIDEO_PALETTE_RGB24:
190 RGB2YUV(window.width, window.height, mmapFrame(), YBuf, UBuf, VBuf, 0);
191 break;
192
193 default:
194 cerr << "invalid palette " <<picture_format.palette << endl;
195 exit(1);
196 }
197
198
199 if (callback)
200 (*callback)(uptr);
201
202}
203
204void V4L1_Base::updateFrame(int /*d*/, void * p)
205{
206
207 ( (V4L1_Base *) (p))->newFrame();
208
209}
210
211int V4L1_Base::start_capturing(char * /*errmsg*/)
212{
213
214 mmapCapture();
215 mmapSync();
216
217 selectCallBackID = IEAddCallback(fd, updateFrame, this);
218 //newFrame();
219 return 0;
220}
221
222int V4L1_Base::stop_capturing(char * /*errmsg*/)
223{
224
225 IERmCallback(selectCallBackID);
226 selectCallBackID = -1;
227 return 0;
228}
229
230int V4L1_Base::getWidth()
231{
232 return window.width;
233}
234
235int V4L1_Base::getHeight()
236{
237 return window.height;
238}
239
240void V4L1_Base::setFPS(int fps)
241{
242 frameRate = fps;
243}
244
245int V4L1_Base::getFPS()
246{
247 return frameRate;
248}
249
250char * V4L1_Base::getDeviceName()
251{
252 return capability.name;
253}
254
255void V4L1_Base::init(int preferedPalette)
256 {
257
258 if (preferedPalette)
259 {
260 picture_format.palette=preferedPalette;
261 if (0 == ioctl(fd, VIDIOCSPICT, &picture_format))
262 cerr << "found preferedPalette " << preferedPalette << endl;
263 else
264 {
265 preferedPalette=0;
266 cerr << "preferedPalette " << preferedPalette << " invalid, trying to find one." << endl;
267 }
268 }
269
270 if (preferedPalette == 0)
271 {
272 do {
273 /* trying VIDEO_PALETTE_YUV420P (Planar) */
274 picture_format.palette=VIDEO_PALETTE_YUV420P;
275 picture_format.depth=12;
276 if (0 == ioctl(fd, VIDIOCSPICT, &picture_format)) {
277 cerr << "found palette VIDEO_PALETTE_YUV420P" << endl;
278 break;
279 }
280 cerr << "VIDEO_PALETTE_YUV420P not supported." << endl;
281 /* trying VIDEO_PALETTE_YUV420 (interlaced) */
282 picture_format.palette=VIDEO_PALETTE_YUV420;
283 picture_format.depth=12;
284 if ( 0== ioctl(fd, VIDIOCSPICT, &picture_format)) {
285 cerr << "found palette VIDEO_PALETTE_YUV420" << endl;
286 break;
287 }
288 cerr << "VIDEO_PALETTE_YUV420 not supported." << endl;
289 /* trying VIDEO_PALETTE_RGB24 */
290 picture_format.palette=VIDEO_PALETTE_RGB24;
291 picture_format.depth=24;
292 if ( 0== ioctl(fd, VIDIOCSPICT, &picture_format)) {
293 cerr << "found palette VIDEO_PALETTE_RGB24" << endl;
294 break;
295 }
296 cerr << "VIDEO_PALETTE_RGB24 not supported." << endl;
297 /* trying VIDEO_PALETTE_GREY */
298 picture_format.palette=VIDEO_PALETTE_GREY;
299 picture_format.depth=8;
300 if ( 0== ioctl(fd, VIDIOCSPICT, &picture_format)) {
301 cerr << "found palette VIDEO_PALETTE_GREY" << endl;
302 break;
303 }
304 cerr << "VIDEO_PALETTE_GREY not supported." << endl;
305 cerr << "could not find a supported palette." << endl;
306 exit(1);
307 } while (false);
308 }
309
310 allocBuffers();
311
312}
313
314void V4L1_Base::allocBuffers()
315{
316 delete YBuf;
317 delete UBuf;
318 delete VBuf;
319 delete colorBuffer;
320
321 YBuf= new unsigned char[window.width * window.height];
322 UBuf= new unsigned char[window.width * window.height];
323 VBuf= new unsigned char[window.width * window.height];
324 colorBuffer = new unsigned char[window.width * window.height * 4];
325}
326
327void V4L1_Base::checkSize(int & x, int & y)
328{
329 if (x >= capability.maxwidth && y >= capability.maxheight)
330 {
331 x=capability.maxwidth;
332 y=capability.maxheight;
333 }
334 else if (x>=352 && y >=288) {
335 x=352;y=288;
336 } else if (x>=320 && y >= 240) {
337 x=320;y=240;
338 } else if (x>=176 && y >=144) {
339 x=176;y=144;
340 } else if (x>=160 && y >=120 ) {
341 x=160;y=120;
342 } else
343 {
344 x=capability.minwidth;
345 y=capability.minheight;
346 }
347}
348
349void V4L1_Base::getMaxMinSize(int & xmax, int & ymax, int & xmin, int & ymin)
350{
351 xmax = capability.maxwidth;
352 ymax = capability.maxheight;
353 xmin = capability.minwidth;
354 ymin = capability.minheight;
355}
356
357bool V4L1_Base::setSize(int x, int y)
358{
359 int oldX, oldY;
360 checkSize(x,y);
361
362 oldX = window.width;
363 oldY = window.height;
364
365 window.width=x;
366 window.height=y;
367
368 cerr << "New size is x=" << window.width << " " << "y=" << window.height <<endl;
369
370 if (ioctl (fd, VIDIOCSWIN, &window))
371 {
372 cerr << "ioctl(VIDIOCSWIN)" << endl;
373 window.width=oldX;
374 window.height=oldY;
375 return false;
376 }
377 ioctl (fd, VIDIOCGWIN, &window);
378
379 allocBuffers();
380
381 return true;
382}
383
384void V4L1_Base::setContrast(int val)
385{
386 picture_format.contrast=val;
387 setPictureSettings();
388}
389
390int V4L1_Base::getContrast()
391{
392 return picture_format.contrast;
393}
394
395void V4L1_Base::setBrightness(int val)
396{
397 picture_format.brightness=val;
398 setPictureSettings();
399}
400
401int V4L1_Base::getBrightness()
402{
403 return picture_format.brightness;
404}
405
406void V4L1_Base::setColor(int val)
407{
408 picture_format.colour=val;
409 setPictureSettings();
410}
411
412int V4L1_Base::getColor()
413{
414 return picture_format.colour;
415}
416
417void V4L1_Base::setHue(int val)
418{
419 picture_format.hue=val;
420 setPictureSettings();
421}
422
423int V4L1_Base::getHue()
424{
425 return picture_format.hue;
426}
427
428void V4L1_Base::setWhiteness(int val)
429{
430 picture_format.whiteness=val;
431 setPictureSettings();
432}
433
434int V4L1_Base::getWhiteness()
435{
436 return picture_format.whiteness;
437}
438
439void V4L1_Base::setPictureSettings()
440{
441 if (ioctl(fd, VIDIOCSPICT, &picture_format) ) {
442 cerr << "setPictureSettings" << endl;
443 }
444 ioctl(fd, VIDIOCGPICT, &picture_format);
445}
446
447void V4L1_Base::getPictureSettings()
448{
449 if (ioctl(fd, VIDIOCGPICT, &picture_format) )
450 {
451 cerr << "getPictureSettings" << endl;
452 }
453}
454
455int V4L1_Base::mmapInit()
456{
457 mmap_buffer.size = 0;
458 mmap_buffer.frames = 0;
459
460 mmap_sync_buffer=-1;
461 mmap_capture_buffer=-1;
462 buffer_start=NULL;
463
464 if (ioctl(fd, VIDIOCGMBUF, &mmap_buffer)) {
465 // mmap not supported
466 return -1;
467 }
468
469 buffer_start = (unsigned char *) mmap (NULL, mmap_buffer.size, PROT_READ, MAP_SHARED, fd, 0);
470
471 if (buffer_start == MAP_FAILED)
472 {
473 cerr << "mmap" << endl;
474 mmap_buffer.size = 0;
475 mmap_buffer.frames = 0;
476 buffer_start=NULL;
477 return -1;
478 }
479
480 return 0;
481}
482
483void V4L1_Base::mmapCapture()
484{
485
486 struct video_mmap vm;
487 mmap_capture_buffer = (mmap_capture_buffer + 1) % mmap_buffer.frames;
488
489 vm.frame = mmap_capture_buffer;
490 vm.format = picture_format.palette;
491 vm.width = window.width;
492 vm.height = window.height;
493
494 if (ioctl(fd, VIDIOCMCAPTURE, &vm) < 0)
495 cerr << "Error V4L1_Base::mmapCapture" << endl;
496}
497
498void V4L1_Base::mmapSync()
499{
500 mmap_sync_buffer= (mmap_sync_buffer + 1) % mmap_buffer.frames;
501
502 if (ioctl(fd, VIDIOCSYNC, &mmap_sync_buffer) < 0)
503 cerr << "Error V4L1_Base::mmapSync()" << endl;
504}
505
506unsigned char * V4L1_Base::mmapFrame()
507{
508 return (buffer_start + mmap_buffer.offsets[mmap_sync_buffer]);
509}
510
511unsigned char * V4L1_Base::getY()
512{
513 return YBuf;
514}
515
516unsigned char * V4L1_Base::getU()
517{
518 return UBuf;
519}
520
521unsigned char * V4L1_Base::getV()
522{
523 return VBuf;
524}
525
526unsigned char * V4L1_Base::getColorBuffer()
527{
528 //cerr << "in get color buffer " << endl;
529
530 switch (picture_format.palette)
531 {
532 case VIDEO_PALETTE_YUV420P:
533 ccvt_420p_bgr32(window.width, window.height,
534 mmapFrame(), (void*)colorBuffer);
535 break;
536
537 case VIDEO_PALETTE_YUYV:
538 ccvt_yuyv_bgr32(window.width, window.height,
539 mmapFrame(), (void*)colorBuffer);
540 break;
541
542 case VIDEO_PALETTE_RGB24:
543 ccvt_rgb24_bgr32(window.width, window.height,
544 mmapFrame(), (void*)colorBuffer);
545 break;
546
547 default:
548 break;
549 }
550
551
552 return colorBuffer;
553
554}
555
556void V4L1_Base::registerCallback(WPF *fp, void *ud)
557{
558 callback = fp;
559 uptr = ud;
560}
Note: See TracBrowser for help on using the repository browser.