source: trunk/MagicSoft/Cosy/videodev/MVideo.cc@ 8859

Last change on this file since 8859 was 8859, checked in by tbretz, 17 years ago
*** empty log message ***
File size: 14.3 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 1/2008 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2008
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MVideo
28//
29// Interface to Video4Linux at a simple level
30//
31/////////////////////////////////////////////////////////////////////////////
32#include "MVideo.h"
33
34// iostream
35#include <iostream>
36
37// open
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <fcntl.h>
41
42#include <unistd.h> // usleep
43#include <errno.h> // errno
44#include <sys/mman.h> // mmap
45#include <sys/ioctl.h> // ioctl
46
47#include <TString.h>
48
49#include "MLog.h"
50#include "MLogManip.h"
51
52using namespace std;
53
54//ClassImp(MVideo);
55
56// -------------------------------------------------------------
57//
58// Constructor. Specify the device (e.g. "/dev/video") to be used
59//
60MVideo::MVideo(const char *path) : fPath(path), fFileDesc(-1), fMapBuffer(0)
61{
62 Reset();
63}
64
65// -------------------------------------------------------------
66//
67// Internal function to reset the descriptors of the device
68//
69void MVideo::Reset()
70{
71 memset(&fCaps, 0, sizeof(fCaps));
72 memset(&fChannel, 0, sizeof(fChannel));
73 memset(&fBuffer, 0, sizeof(fBuffer));
74
75 fFileDesc = -1;
76 fMapBuffer = 0;
77 fChannel.channel = -1;
78}
79
80// -------------------------------------------------------------
81//
82// Mapper around ioctl for easier access to the device
83//
84int MVideo::Ioctl(int req, void *opt, bool allowirq) const
85{
86 if (fFileDesc<0)
87 {
88 gLog << err << "ERROR - Ioctl: Device " << fPath << " not open." << endl;
89 return -1;
90 }
91
92 while (1)
93 {
94 // FIXME: This call is a possible source for a hangup
95 const int rc = ioctl(fFileDesc, req, opt);
96 if (rc>=0)
97 return rc;
98
99 // errno== 4: Interrupted system call (e.g. by alarm())
100 // errno==16: Device or resource busy
101 if (errno==4 || errno==16)
102 {
103 if (!allowirq && errno==4)
104 return -4;
105
106 gLog << err << "ERROR - MVideo::Ioctl 0x" << hex << req << ": errno=" << dec << errno << " - ";
107 gLog << strerror(errno) << " (rc=" << rc << ")" << endl;
108 usleep(10);
109 continue;
110 }
111
112 gLog << err << "ERROR - MVideo::Ioctl 0x" << hex << req << ": errno=" << dec << errno << " - ";
113 gLog << strerror(errno) << " (rc=" << rc << ")" << endl;
114 return rc;
115 }
116 return -1;
117}
118
119// -------------------------------------------------------------
120//
121// Read the capabilities of the device
122//
123Bool_t MVideo::GetCapabilities()
124{
125 return Ioctl(VIDIOCGCAP, &fCaps)!=-1;
126}
127
128// -------------------------------------------------------------
129//
130// Read the properties of the device
131//
132Bool_t MVideo::GetProperties()
133{
134 return Ioctl(VIDIOCGPICT, &fProp)!=-1;
135}
136
137// -------------------------------------------------------------
138//
139// Open channel ch of the device
140//
141Bool_t MVideo::Open(Int_t ch)
142{
143 Bool_t rc = Init(ch);
144 if (!rc)
145 Close();
146 return rc;
147}
148
149// -------------------------------------------------------------
150//
151// Open a channel of the device and retriev all necessary
152// informations from the driver. Initialize the shared
153// memory. Other access methods are not supported yet.
154//
155Bool_t MVideo::Init(Int_t channel)
156{
157 if (IsOpen())
158 {
159 gLog << warn << "WARNING - Device " << fPath << " already open." << endl;
160 return kTRUE;
161 }
162
163 gLog << all << "Opening " << fPath << "... " << flush;
164 do
165 {
166 fFileDesc = open(fPath, O_RDWR);
167 usleep(1);
168 }
169 while (errno==19 && fFileDesc==-1);
170
171 if (fFileDesc == -1)
172 {
173 gLog << err << "ERROR: " << strerror(errno) << endl;
174 return kFALSE;
175 }
176
177 gLog << "done (" << fFileDesc << ")." << endl;
178
179 // Close device on exit
180 if (fcntl(fFileDesc, F_SETFD, FD_CLOEXEC)<0)
181 {
182 gLog << err << "ERROR - Call to fnctl (F_SETFD, FD_CLOEXEC) failed." << endl;
183 return kFALSE;
184 }
185
186 if (!GetCapabilities())
187 {
188 gLog << err << "ERROR - Getting device capabilities failed." << endl;
189 return kFALSE;
190 }
191
192 if (!SetChannel(channel))
193 return kFALSE;
194
195 if (!GetProperties())
196 {
197 gLog << err << "ERROR - Couldn't get picture properties." << endl;
198 return kFALSE;
199 }
200
201 // get mmap grab buffer info
202 if (Ioctl(VIDIOCGMBUF, &fBuffer)==-1)
203 {
204 gLog << err << "ERROR - Couldn't get info about memory map buffer." << endl;
205 return kFALSE;
206 }
207
208 // map file (device) into memory
209 fMapBuffer = (char*)mmap(0, fBuffer.size, PROT_READ|PROT_WRITE, MAP_SHARED, fFileDesc, 0);
210 if (fMapBuffer == (void*)-1)
211 {
212 gLog << err << "ERROR - Couldn't map device buffer into memory." << endl;
213 fMapBuffer = 0;
214 return kFALSE;
215 }
216
217 Print();
218
219 return kTRUE;
220}
221
222// -------------------------------------------------------------
223//
224// Close device. Free the shared memory
225//
226Int_t MVideo::Close()
227{
228 // if (!IsOpen())
229 // return kTRUE;
230
231 Bool_t rc = kTRUE;
232
233 gLog << all << "Closing " << fPath << " (" << fFileDesc << ")... " << flush;
234 if (fFileDesc != -1)
235 {
236 if (close(fFileDesc)<0)
237 {
238 gLog << err << "ERROR!" << endl;
239 rc = kFALSE;
240 }
241 fFileDesc = -1;
242 }
243 gLog << "done." << endl;
244
245 // unmap device memory
246 if (fMapBuffer)
247 munmap(fMapBuffer, fBuffer.size);
248
249 Reset();
250
251 return rc;
252}
253
254// -------------------------------------------------------------
255//
256// Instruct hardware to start capture into framebuffer frame
257//
258Bool_t MVideo::CaptureStart(unsigned int frame) const
259{
260 struct video_mmap gb =
261 {
262 frame%fBuffer.frames, // frame
263 fCaps.maxheight, fCaps.maxwidth, // height, width
264 VIDEO_PALETTE_RGB24 // palette
265 };
266
267 //
268 // capture frame
269 //
270 if (Ioctl(VIDIOCMCAPTURE, &gb) != -1)
271 return kTRUE;
272
273// if (errno == EAGAIN)
274 gLog << err;
275 gLog << "ERROR - Couldn't start capturing frame " << frame << " - unable to sync." << endl;
276 gLog << " Maybe your card doesn't support VIDEO_PALETTE_RGB24." << endl;
277
278 return kFALSE;
279}
280
281// -------------------------------------------------------------
282//
283// Wait until hardware has finished capture into framebuffer frame
284//
285Int_t MVideo::CaptureWait(unsigned int frame, char **ptr) const
286{
287 frame %= fBuffer.frames;
288
289 *ptr = NULL;
290
291 const int SYNC_TIMEOUT = 1;
292
293 alarm(SYNC_TIMEOUT);
294 const Int_t rc = Ioctl(VIDIOCSYNC, &frame, false);
295 if (rc==-4)
296 {
297 //cout << "ERROR - Waiting for frame " << frame << " timed out." << endl;
298 return kSKIP;
299 }
300 alarm(0);
301
302 if (rc==-1)
303 {
304 gLog << err << "ERROR - Waiting for captured frame failed." << endl;
305 return kFALSE;
306 }
307
308 *ptr = fMapBuffer+fBuffer.offsets[frame];
309
310 return kTRUE;
311}
312
313// -------------------------------------------------------------
314//
315// Change the channel of a priviously opened device
316//
317Bool_t MVideo::SetChannel(Int_t chan)
318{
319 if (fChannel.channel==chan)
320 return kTRUE;
321
322 if (chan<0 || chan>=fCaps.channels)
323 {
324 gLog << err << "ERROR - Set channel " << chan << " out of range." << endl;
325 return kFALSE;
326 }
327
328 // Switch to channel
329 struct video_channel ch = { chan, "", 0, 0, 0, 0 };
330 if (Ioctl(VIDIOCSCHAN, &ch)==-1)
331 {
332 gLog << err << "ERROR - Couldn't switch to channel " << chan << "." << endl;
333 gLog << " You might need a bttv version > 0.5.13" << endl;
334 return kFALSE;
335 }
336
337 // Get information about channel
338 if (Ioctl(VIDIOCGCHAN, &ch)==-1)
339 {
340 gLog << err << "ERROR - Getting information for channel " << chan << " failed." << endl;
341 return kFALSE;
342 }
343
344 memcpy(&fChannel, &ch, sizeof(fChannel));
345
346 gLog << all << "Switched to channel " << chan << endl;
347
348 return kTRUE;
349}
350
351// -------------------------------------------------------------
352//
353// Has the device capture capabilities?
354//
355Bool_t MVideo::CanCapture() const
356{
357 return fCaps.type&VID_TYPE_CAPTURE;
358}
359
360// -------------------------------------------------------------
361//
362// Returns the number of frame buffers which can be used
363//
364Int_t MVideo::GetNumBuffers() const
365{
366 return fBuffer.frames;
367}
368
369// -------------------------------------------------------------
370//
371// Maximum width of the frame which can be captured
372//
373Int_t MVideo::GetWidth() const
374{
375 return fCaps.maxwidth;
376}
377
378// -------------------------------------------------------------
379//
380// Maximum height of the frame which can be captured
381//
382Int_t MVideo::GetHeight() const
383{
384 return fCaps.maxheight;
385}
386
387// -------------------------------------------------------------
388//
389// Return the device type as string
390//
391TString MVideo::GetDevType(int type) const
392{
393 TString rc;
394 if (CanCapture())
395 rc += " capture";
396 if (type&VID_TYPE_TUNER)
397 rc += " tuner";
398 if (type&VID_TYPE_TELETEXT)
399 rc += " teletext";
400 if (type&VID_TYPE_OVERLAY)
401 rc += " overlay";
402 if (type&VID_TYPE_CHROMAKEY)
403 rc += " chromakey";
404 if (type&VID_TYPE_CLIPPING)
405 rc += " clipping";
406 if (type&VID_TYPE_FRAMERAM)
407 rc += " frameram";
408 if (type&VID_TYPE_SCALES)
409 rc += " scales";
410 if (type&VID_TYPE_MONOCHROME)
411 rc += " monochrom";
412 if (type&VID_TYPE_SUBCAPTURE)
413 rc += " subcapature";
414 return rc;
415}
416
417// -------------------------------------------------------------
418//
419// Return the channel flags as string
420//
421TString MVideo::GetChannelFlags(Int_t flags) const
422{
423 TString rc = "video";
424 if (flags&VIDEO_VC_TUNER)
425 rc += " tuner";
426 if (flags&VIDEO_VC_AUDIO)
427 rc += " audio";
428 return rc;
429}
430
431// -------------------------------------------------------------
432//
433// Return the channel type as string
434//
435TString MVideo::GetChannelType(Int_t type) const
436{
437 if (type&VIDEO_TYPE_TV)
438 return "TV";
439 if (type&VIDEO_TYPE_CAMERA)
440 return "camera";
441 return "unknown";
442}
443
444// -------------------------------------------------------------
445//
446// Return the palette pal as string
447//
448TString MVideo::GetPalette(Int_t pal) const
449{
450 if (pal&VIDEO_PALETTE_GREY)
451 return "Linear intensity grey scale";
452 if (pal&VIDEO_PALETTE_HI240)
453 return "BT848 8-bit color cube";
454 if (pal&VIDEO_PALETTE_RGB565)
455 return "RGB565 packed into 16-bit words";
456 if (pal&VIDEO_PALETTE_RGB555)
457 return "RGB555 packed into 16-bit words, top bit undefined";
458 if (pal&VIDEO_PALETTE_RGB24)
459 return "RGB888 packed into 24-bit words";
460 if (pal&VIDEO_PALETTE_RGB32)
461 return "RGB888 packed into the low three bytes of 32-bit words. Top bits undefined.";
462 if (pal&VIDEO_PALETTE_YUV422)
463 return "Video style YUV422 - 8-bit packed, 4-bit Y, 2-bits U, 2-bits V";
464 if (pal&VIDEO_PALETTE_YUYV)
465 return "YUYV";
466 if (pal&VIDEO_PALETTE_UYVY)
467 return "UYVY";
468 if (pal&VIDEO_PALETTE_YUV420)
469 return "YUV420";
470 if (pal&VIDEO_PALETTE_YUV411)
471 return "YUV411";
472 if (pal&VIDEO_PALETTE_RAW)
473 return "Raw capture (Bt848)";
474 if (pal&VIDEO_PALETTE_YUV422P)
475 return "YUV 4:2:2 planar";
476 if (pal&VIDEO_PALETTE_YUV411P)
477 return "YUV 4:1:1 planar";
478
479 return "unknown";
480}
481
482// -------------------------------------------------------------
483//
484// Print informations about the device, the capabilities, the
485// channel and all available information
486//
487void MVideo::Print() const
488{
489 gLog << all;
490
491 gLog << "Device " << fPath << " " << (IsOpen()?"open":"closed") << "." << endl;
492
493 if (!IsOpen())
494 return;
495
496 gLog << " - Name: " << fCaps.name << endl;
497 gLog << " - DevType: " << GetDevType(fCaps.type) << endl;
498 gLog << " - Channels: " << fCaps.channels << endl;
499 gLog << " - Audios: " << fCaps.audios << endl;
500 gLog << " - Size: ";
501 gLog << fCaps.minwidth << "x" << fCaps.minheight << " to ";
502 gLog << fCaps.maxwidth << "x" << fCaps.maxheight << endl;
503 gLog << endl;
504 if (fChannel.channel>=0)
505 {
506 gLog << " - Channel: " << fChannel.channel << " (" << fChannel.name << ")" << endl;
507 gLog << " - IsA: " << GetChannelType(fChannel.type) << " with " << GetChannelFlags(fChannel.flags) << endl;
508 //if (fChannel.flags&VIDEO_VC_NORM)
509 gLog << " - Norm: " << fChannel.norm << endl;
510 gLog << endl;
511 }
512 gLog << " - Brightness: " << fProp.brightness << endl;
513 gLog << " - Hue: " << fProp.hue << endl;
514 gLog << " - Color: " << fProp.colour << endl;
515 gLog << " - Contrast: " << fProp.contrast << endl;
516 gLog << " - Whiteness: " << fProp.whiteness << endl;
517 gLog << " - Depth: " << fProp.depth << endl;
518 gLog << " - Palette: " << GetPalette(fProp.palette) << " (" << fProp.palette << ")" << endl;
519 gLog << endl;
520
521 gLog << " - BufferSize: 0x" << hex << fBuffer.size << " (" << dec << fBuffer.frames << " frames)" << endl;
522 gLog << " - Offsets: " << hex;
523 for (int i=0; i<fBuffer.frames; i++)
524 gLog << " 0x" << fBuffer.offsets[i];
525 gLog << dec << endl;
526}
527
528/*
529void MVideo::SetPicPar(int bright, int hue, int contrast)
530{
531 struct video_picture pict;
532
533 Ioctl(VIDIOCGPICT, &pict); // get
534
535 if (contrast != -1)
536 pict.contrast = contrast;
537
538 if (bright != -1)
539 pict.brightness = bright;
540
541 if (hue != -1)
542 pict.hue = hue;
543
544 Ioctl(VIDIOCSPICT, &pict); //set
545}
546
547void MVideo::GetPicPar(int *bright, int *hue, int *contrast)
548{
549 struct video_picture pict;
550
551 Ioctl(VIDIOCGPICT, &pict); // get
552
553 *contrast = pict.contrast;
554 *bright = pict.brightness;
555 *hue = pict.hue;
556}
557*/
Note: See TracBrowser for help on using the repository browser.