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

Last change on this file since 8849 was 8849, checked in by tbretz, 18 years ago
*** empty log message ***
File size: 14.1 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 -ioctl returned rc=" << rc << " '";
107 gLog << strerror(errno) << "' (errno = " << errno << ")" << endl;
108 usleep(10);
109 continue;
110 }
111
112 gLog << err << "ERROR - MVideo::Ioctl " << 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!" << 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 << "ERROR - Couldn't start capturing frame " << frame << " - unable to sync." << endl;
275
276 return kFALSE;
277}
278
279// -------------------------------------------------------------
280//
281// Wait until hardware has finished capture into framebuffer frame
282//
283Int_t MVideo::CaptureWait(unsigned int frame, char **ptr) const
284{
285 frame %= fBuffer.frames;
286
287 *ptr = NULL;
288
289 const int SYNC_TIMEOUT = 1;
290
291 alarm(SYNC_TIMEOUT);
292 const Int_t rc = Ioctl(VIDIOCSYNC, &frame, false);
293 if (rc==-4)
294 {
295 //cout << "ERROR - Waiting for frame " << frame << " timed out." << endl;
296 return kSKIP;
297 }
298 alarm(0);
299
300 if (rc==-1)
301 {
302 gLog << err << "ERROR - Waiting for captured frame failed." << endl;
303 return kFALSE;
304 }
305
306 *ptr = fMapBuffer+fBuffer.offsets[frame];
307
308 return kTRUE;
309}
310
311// -------------------------------------------------------------
312//
313// Change the channel of a priviously opened device
314//
315Bool_t MVideo::SetChannel(Int_t chan)
316{
317 if (fChannel.channel==chan)
318 return kTRUE;
319
320 if (chan<0 || chan>=fCaps.channels)
321 {
322 gLog << err << "ERROR - Set channel " << chan << " out of range." << endl;
323 return kFALSE;
324 }
325
326 // Switch to channel
327 struct video_channel ch = { chan, "", 0, 0, 0, 0 };
328 if (Ioctl(VIDIOCSCHAN, &ch)==-1)
329 {
330 gLog << err << "ERROR - Couldn't switch to channel " << chan << "." << endl;
331 gLog << " You might need a bttv version > 0.5.13" << endl;
332 return kFALSE;
333 }
334
335 // Get information about channel
336 if (Ioctl(VIDIOCGCHAN, &ch)==-1)
337 {
338 gLog << err << "ERROR - Getting information for channel " << chan << " failed." << endl;
339 return kFALSE;
340 }
341
342 memcpy(&fChannel, &ch, sizeof(fChannel));
343
344 return kTRUE;
345}
346
347// -------------------------------------------------------------
348//
349// Has the device capture capabilities?
350//
351Bool_t MVideo::CanCapture() const
352{
353 return fCaps.type&VID_TYPE_CAPTURE;
354}
355
356// -------------------------------------------------------------
357//
358// Returns the number of frame buffers which can be used
359//
360Int_t MVideo::GetNumBuffers() const
361{
362 return fBuffer.frames;
363}
364
365// -------------------------------------------------------------
366//
367// Maximum width of the frame which can be captured
368//
369Int_t MVideo::GetWidth() const
370{
371 return fCaps.maxwidth;
372}
373
374// -------------------------------------------------------------
375//
376// Maximum height of the frame which can be captured
377//
378Int_t MVideo::GetHeight() const
379{
380 return fCaps.maxheight;
381}
382
383// -------------------------------------------------------------
384//
385// Return the device type as string
386//
387TString MVideo::GetDevType(int type) const
388{
389 TString rc;
390 if (CanCapture())
391 rc += " capture";
392 if (type&VID_TYPE_TUNER)
393 rc += " tuner";
394 if (type&VID_TYPE_TELETEXT)
395 rc += " teletext";
396 if (type&VID_TYPE_OVERLAY)
397 rc += " overlay";
398 if (type&VID_TYPE_CHROMAKEY)
399 rc += " chromakey";
400 if (type&VID_TYPE_CLIPPING)
401 rc += " clipping";
402 if (type&VID_TYPE_FRAMERAM)
403 rc += " frameram";
404 if (type&VID_TYPE_SCALES)
405 rc += " scales";
406 if (type&VID_TYPE_MONOCHROME)
407 rc += " monochrom";
408 if (type&VID_TYPE_SUBCAPTURE)
409 rc += " subcapature";
410 return rc;
411}
412
413// -------------------------------------------------------------
414//
415// Return the channel flags as string
416//
417TString MVideo::GetChannelFlags(Int_t flags) const
418{
419 TString rc = "video";
420 if (flags&VIDEO_VC_TUNER)
421 rc += " tuner";
422 if (flags&VIDEO_VC_AUDIO)
423 rc += " audio";
424 return rc;
425}
426
427// -------------------------------------------------------------
428//
429// Return the channel type as string
430//
431TString MVideo::GetChannelType(Int_t type) const
432{
433 if (type&VIDEO_TYPE_TV)
434 return "TV";
435 if (type&VIDEO_TYPE_CAMERA)
436 return "camera";
437 return "unknown";
438}
439
440// -------------------------------------------------------------
441//
442// Return the palette pal as string
443//
444TString MVideo::GetPalette(Int_t pal) const
445{
446 if (pal&VIDEO_PALETTE_GREY)
447 return "Linear intensity grey scale";
448 if (pal&VIDEO_PALETTE_HI240)
449 return "BT848 8-bit color cube";
450 if (pal&VIDEO_PALETTE_RGB565)
451 return "RGB565 packed into 16-bit words";
452 if (pal&VIDEO_PALETTE_RGB555)
453 return "RGB555 packed into 16-bit words, top bit undefined";
454 if (pal&VIDEO_PALETTE_RGB24)
455 return "RGB888 packed into 24-bit words";
456 if (pal&VIDEO_PALETTE_RGB32)
457 return "RGB888 packed into the low three bytes of 32-bit words. Top bits undefined.";
458 if (pal&VIDEO_PALETTE_YUV422)
459 return "Video style YUV422 - 8-bit packed, 4-bit Y, 2-bits U, 2-bits V";
460 if (pal&VIDEO_PALETTE_YUYV)
461 return "YUYV";
462 if (pal&VIDEO_PALETTE_UYVY)
463 return "UYVY";
464 if (pal&VIDEO_PALETTE_YUV420)
465 return "YUV420";
466 if (pal&VIDEO_PALETTE_YUV411)
467 return "YUV411";
468 if (pal&VIDEO_PALETTE_RAW)
469 return "Raw capture (Bt848)";
470 if (pal&VIDEO_PALETTE_YUV422P)
471 return "YUV 4:2:2 planar";
472 if (pal&VIDEO_PALETTE_YUV411P)
473 return "YUV 4:1:1 planar";
474
475 return "unknown";
476}
477
478// -------------------------------------------------------------
479//
480// Print informations about the device, the capabilities, the
481// channel and all available information
482//
483void MVideo::Print() const
484{
485 gLog << all;
486
487 gLog << "Device " << fPath << " " << (IsOpen()?"open":"closed") << "." << endl;
488
489 if (!IsOpen())
490 return;
491
492 gLog << " - Name: " << fCaps.name << endl;
493 gLog << " - DevType: " << GetDevType(fCaps.type) << endl;
494 gLog << " - Channels: " << fCaps.channels << endl;
495 gLog << " - Audios: " << fCaps.audios << endl;
496 gLog << " - Size: ";
497 gLog << fCaps.minwidth << "x" << fCaps.minheight << " to ";
498 gLog << fCaps.maxwidth << "x" << fCaps.maxheight << endl;
499 gLog << endl;
500 if (fChannel.channel>=0)
501 {
502 gLog << " - Channel: " << fChannel.channel << " (" << fChannel.name << ")" << endl;
503 gLog << " - IsA: " << GetChannelType(fChannel.type) << " with " << GetChannelFlags(fChannel.flags) << endl;
504 //if (fChannel.flags&VIDEO_VC_NORM)
505 gLog << " - Norm: " << fChannel.norm << endl;
506 gLog << endl;
507 }
508 gLog << " - Brightness: " << fProp.brightness << endl;
509 gLog << " - Hue: " << fProp.hue << endl;
510 gLog << " - Color: " << fProp.colour << endl;
511 gLog << " - Contrast: " << fProp.contrast << endl;
512 gLog << " - Whiteness: " << fProp.whiteness << endl;
513 gLog << " - Depth: " << fProp.depth << endl;
514 gLog << " - Palette: " << GetPalette(fProp.palette) << " (" << fProp.palette << ")" << endl;
515 gLog << endl;
516
517 gLog << " - BufferSize: 0x" << hex << fBuffer.size << " (" << dec << fBuffer.frames << " frames)" << endl;
518 gLog << " - Offsets: " << hex;
519 for (int i=0; i<fBuffer.frames; i++)
520 gLog << " 0x" << fBuffer.offsets[i];
521 gLog << dec << endl;
522}
523
524/*
525void MVideo::SetPicPar(int bright, int hue, int contrast)
526{
527 struct video_picture pict;
528
529 Ioctl(VIDIOCGPICT, &pict); // get
530
531 if (contrast != -1)
532 pict.contrast = contrast;
533
534 if (bright != -1)
535 pict.brightness = bright;
536
537 if (hue != -1)
538 pict.hue = hue;
539
540 Ioctl(VIDIOCSPICT, &pict); //set
541}
542
543void MVideo::GetPicPar(int *bright, int *hue, int *contrast)
544{
545 struct video_picture pict;
546
547 Ioctl(VIDIOCGPICT, &pict); // get
548
549 *contrast = pict.contrast;
550 *bright = pict.brightness;
551 *hue = pict.hue;
552}
553*/
Note: See TracBrowser for help on using the repository browser.