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

Last change on this file since 614 was 490, checked in by campagne, 14 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.