source: trunk/MagicSoft/Cosy/videodev/Camera.cc@ 8304

Last change on this file since 8304 was 7787, checked in by tbretz, 18 years ago
*** empty log message ***
File size: 7.6 KB
Line 
1#include "Camera.h"
2
3#include <iostream>
4#include <errno.h> // errono
5#include <pthread.h>
6#include <sys/ioctl.h> // ioctl
7#include <sys/mman.h> // PROT_READ
8
9#include "MStopwatch.h"
10
11#include "videodev.h"
12
13ClassImp(Camera);
14
15using namespace std;
16
17inline int Camera::Ioctl(int req, void *opt, const char *str)
18{
19 if (fd<0)
20 {
21 cout << "Error! Called Ioctl with invalid filedescriptor." << endl;
22 return -1;
23 }
24
25 while (1)
26 {
27 const int rc = ioctl(fd, req, opt);
28 if (rc>=0)
29 return rc;
30
31 // errno== 4: Interrupted system call
32 // errno==16: Device or resource busy
33 if (errno==4 || errno==16)
34 {
35 cout << "Camera: ioctl returned rc=" << rc << " '";
36 cout << (str?str:strerror(errno)) << "' (errno = " << errno << ")" << endl;
37 usleep(10);
38 continue;
39 }
40
41 cout << "Error! Ioctl " << hex << req << ": errno=" << dec << errno << " - ";
42 cout << (str?str:strerror(errno)) << " (rc=" << rc << ")" << endl;
43 return rc;
44 }
45 return -1;
46}
47
48void Camera::Error(const char *str, int fatal)
49{
50 cout << endl;
51 cout << (fatal?"Fatal ":"") << "Error! " << str << ": " << strerror(errno);
52 cout << endl;
53
54 if (fatal)
55 exit(1);
56}
57void Camera::SigInit()
58{
59 /*
60 struct sigaction act, old;
61
62 memset(&act, 0, sizeof(act));
63
64 act.sa_handler = SigAlarm;
65
66 sigemptyset(&act. sa_mask);
67 sigaction(SIGALRM, &act, &old);
68
69 // signal(SIGINT, ctrlc);
70 */
71}
72
73void Camera::SigAlarm(int signal)
74{
75 cout << "Camera: oops: got sigalarm" << endl;
76 exit(1);
77}
78
79char *Camera::GetImg(unsigned int frame)
80{
81 // wait until grabbing is finished??
82 //
83 // give signal SIGALARM
84 const int SYNC_TIMEOUT = 1;
85
86 alarm(SYNC_TIMEOUT);
87 Ioctl(VIDIOCSYNC, &frame); // sync with mmap grabbing
88 alarm(0);
89
90 return pMapBuffer+iOffsets[frame];
91}
92
93int Camera::StartGrab(unsigned int frame)
94{
95 // We could also get RGB555, RGB565 and RGB32. But we want
96 // RGB24 because we have a 8bit DAC which gives us 8bit per
97 // color ==> RGB24 which is in the following the most simple
98 // to process.
99 static struct video_mmap gb =
100 {
101 0, // frame
102 rows, cols, // height, width
103 VIDEO_PALETTE_RGB24 // palette
104 };
105
106 gb.frame = frame&1;
107
108 //
109 // capture frame
110 //
111 if (Ioctl(VIDIOCMCAPTURE, &gb) != -1)
112 return true;
113
114 if (errno == EAGAIN)
115 cout << "Grabber chip can't sync" << endl;
116
117 return false;
118}
119
120Camera::Camera(PixClient &client, Int_t nch) : fd(-1), iBufferSize(0), fClient(client), fCond(), fMutex(fCond.GetMutex())
121{
122 cout << "Camera: " << this << " /dev/video: opening..." << flush;
123
124 //
125 // ------ Open device /dev/video ------
126 //
127 do
128 {
129 fd = open("/dev/video", O_RDWR);
130 usleep(1);
131 }
132 while (errno==19 && fd==-1);
133
134 if (fd == -1)
135 Error("open /dev/video");
136
137 fcntl(fd, F_SETFD, FD_CLOEXEC); // Close device on exit
138 SigInit();
139
140 //
141 // get input channel 0 information
142 //
143
144 struct video_channel ch;
145 ch.channel = nch;
146 Ioctl(VIDIOCGCHAN, &ch);
147
148 //
149 // ioctl probe, switch to input 0
150 //
151 Ioctl(VIDIOCSCHAN, &ch, "You need a bttv version > 0.5.13");
152
153 //
154 // map grab buffer, get size and offset
155 //
156 struct video_mbuf buffers;
157 Ioctl(VIDIOCGMBUF, &buffers);
158
159 iBufferSize = buffers.size;
160 iOffsets[0] = buffers.offsets[0];
161 iOffsets[1] = buffers.offsets[1];
162
163 //
164 // map file (device) into memory
165 //
166 pMapBuffer = (char*)mmap(0, iBufferSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
167
168 if ((int)pMapBuffer == -1)
169 Error("mmap");
170
171 cout << "OK." << endl;
172
173 cout << "Buffer Address: " << (void*)pMapBuffer << endl;
174 cout << "Buffer Offset 1: " << (void*)iOffsets[0] << endl;
175 cout << "Buffer Offset 2: " << (void*)iOffsets[1] << endl;
176 cout << "Buffer Size: " << (void*)iBufferSize << endl;
177 cout << "grab: use: 768x576 24 bit TrueColor (LE: bgr) = " << (void*)(768*576*3) << "b" << endl;
178
179// if (fMutex->UnLock()==13)
180// cout << "Camera::Camera - tried to unlock mutex locked by other thread." << endl;
181
182 cout << "Starting thread..." << flush;
183 //pthread_cond_init(&fCond, NULL);
184 //pthread_mutex_init(&fMux, NULL);
185 //pthread_mutex_lock(&fMux);
186// if (fMutex->Lock()==13)
187// cout << "Camera::Camera - mutex is already locked by this thread" << endl;
188 pthread_create(&fThread, NULL, MapThread, this);
189 cout << "CameraInitialized..." << endl;
190
191}
192
193Camera::~Camera()
194{
195 pthread_cancel(fThread);
196
197 cout << "/dev/video: closing... " << flush;
198 if (fd != -1)
199 {
200 close(fd);
201 fd = -1;
202 }
203 cout << "done." << endl;
204
205 // unmap device memory
206 if ((int)pMapBuffer != -1)
207 munmap(pMapBuffer, iBufferSize);
208}
209
210void *Camera::MapThread(void *arg)
211{
212 Camera *cam = (Camera*)arg;
213
214 // setpriority(PRIO_PROCESS, 0, 10);
215 pthread_detach(pthread_self());
216
217 cam->Thread();
218
219 return 0;
220}
221
222void Camera::ExitLoop()
223{
224 fStop = 1;
225 while (IsRunning())
226 usleep(1);
227}
228
229//
230// flag if the execution is running or not
231//
232int Camera::IsRunning() const
233{
234 const Int_t rc = fMutex->TryLock();
235 if (rc==0)
236 return false;
237
238 if (rc==13)
239 return false;
240
241 fMutex->UnLock();
242 return true;
243}
244
245void Camera::LoopStep(const unsigned long n)
246{
247 char *img = GetImg(n&1);
248
249 gettimeofday(&fTime, NULL);
250
251 const char *end = img + cols*rows*depth;
252 char *beg = fImg;
253
254 while (img < end)
255 {
256 *beg++ = *img;
257 img += depth;
258 }
259}
260
261void Camera::Thread()
262{
263#define IsOdd(i) (2*(i/2)!=i)
264 cout << "Camera::Thread started..." << endl;
265 while (1)
266 {
267 fCond.Wait();;
268 if (fd==-1)
269 break;
270
271 MStopwatch t;
272 t.Start();
273
274 unsigned long i=0;
275
276 if (!StartGrab(0))
277 continue;
278
279 if (!StartGrab(1))
280 continue;
281
282 while (!(fStop || fNum && i==fNum-2))
283 {
284 LoopStep(i);
285 if (!StartGrab(i&1))
286 break;
287
288 fClient.ProcessFrame(i, (byte*)fImg, &fTime);
289 i++;
290 }
291
292 if (!IsOdd(i))
293 {
294 LoopStep(i);
295 fClient.ProcessFrame(i, (byte*)fImg, &fTime);
296 i++;
297 }
298
299 LoopStep(i);
300 fClient.ProcessFrame(i, (byte*)fImg, &fTime);
301 i++;
302
303 //
304 // Wait until processing of frame 1 finished.
305 //
306 t.Stop();
307 t.Print(i);
308 }
309
310 fMutex->UnLock();
311
312 cout << "Camera::Thread.. stopped." << endl;
313}
314
315void Camera::Loop(unsigned long nof)
316{
317 if (2*(nof/2) != nof)
318 {
319 cout << "Sorry, only even values are allowed!" << endl;
320 return;
321 }
322
323 ExitLoop();
324
325 fNum = nof;
326 fStop = 0;
327
328 //
329 // Start execution
330 //
331 fCond.Broadcast();
332
333 // I don't know what the reason for this line is, but it
334 // seems to solve some starnge crashes when switching
335 // between the two cameras and it ensures that cosy works
336 // with root 4.04/02g
337 fMutex->UnLock();
338}
339
340void Camera::SetPicPar(int bright, int hue, int contrast)
341{
342 struct video_picture pict;
343
344 Ioctl(VIDIOCGPICT, &pict); // get
345
346 if (contrast != -1)
347 pict.contrast = contrast;
348
349 if (bright != -1)
350 pict.brightness = bright;
351
352 if (hue != -1)
353 pict.hue = hue;
354
355 Ioctl(VIDIOCSPICT, &pict); //set
356}
357
358void Camera::GetPicPar(int *bright, int *hue, int *contrast)
359{
360 struct video_picture pict;
361
362 Ioctl(VIDIOCGPICT, &pict); // get
363
364 *contrast = pict.contrast;
365 *bright = pict.brightness;
366 *hue = pict.hue;
367}
368
Note: See TracBrowser for help on using the repository browser.