source: trunk/Cosy/videodev/MVideo.cc@ 19752

Last change on this file since 19752 was 16766, checked in by tbretz, 11 years ago
Changed to use v4l2.
File size: 31.7 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:thomas.bretz@epfl.ch>
19!
20! Copyright: MAGIC Software Development, 2000-2011
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MVideo
28//
29// Interface to Video4Linux at a simple level
30//
31// V4L2 spcifications from http://v4l2spec.bytesex.org/spec/
32//
33/////////////////////////////////////////////////////////////////////////////
34#include "MVideo.h"
35
36// iostream
37#include <iostream>
38
39// open
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <fcntl.h>
43
44#include <unistd.h> // usleep
45#include <errno.h> // errno
46#include <sys/mman.h> // mmap
47#include <sys/ioctl.h> // ioctl
48
49#include <TEnv.h>
50#include <TString.h>
51
52#include "MLog.h"
53#include "MLogManip.h"
54
55#undef DEBUG
56
57using namespace std;
58
59//ClassImp(MVideo);
60
61MVideoCtrl::MVideoCtrl(const v4l2_queryctrl &ctrl)
62{
63 fId = ctrl.id;
64 fName = (const char*)ctrl.name;
65 fMinimum = ctrl.minimum;
66 fMaximum = ctrl.maximum;
67 fStep = ctrl.step;
68 fDefault = ctrl.default_value;
69}
70
71// -------------------------------------------------------------
72//
73// Constructor. Specify the device (e.g. "/dev/video") to be used
74//
75MVideo::MVideo(const char *path) : fPath(path), fFileDesc(-1), fMapBuffer(0)
76{
77 Reset();
78
79 fControls.SetOwner();
80}
81
82// -------------------------------------------------------------
83//
84// Internal function to reset the descriptors of the device
85//
86void MVideo::Reset()
87{
88 fInputs.clear();
89 fStandards.clear();
90
91 memset(&fCaps, 0, sizeof(fCaps));
92 memset(&fChannel, 0, sizeof(fChannel));
93// memset(&fBuffer, 0, sizeof(fBuffer));
94 memset(&fAbil, 0, sizeof(fAbil));
95
96 fFileDesc = -1;
97 fMapBuffer = 0;
98 fChannel.channel = -1;
99 fAbil.tuner = -1;
100
101 fControls.Delete();
102}
103
104// -------------------------------------------------------------
105//
106// Mapper around ioctl for easier access to the device
107//
108int MVideo::Ioctl(int req, void *opt, bool allowirq, bool force) const
109{
110 if (fFileDesc<0)
111 {
112 gLog << err << "ERROR - Ioctl: Device " << fPath << " not open." << endl;
113 return -1;
114 }
115
116 while (1)
117 {
118 // FIXME: This call is a possible source for a hangup
119 const int rc = ioctl(fFileDesc, req, opt);
120 if (rc==0)
121 return 0;
122
123 if (errno==EINVAL)
124 return 1;
125
126 if (!allowirq && errno==EAGAIN)
127 return -4;
128
129 cout <<"errno="<< errno << endl;
130
131 // errno== 4: Interrupted system call (e.g. by alarm())
132 // errno==16: Device or resource busy
133 if (errno==4 || errno==16)
134 {
135 if (!allowirq && errno==4)
136 return -4;
137
138 gLog << err << "ERROR - MVideo::Ioctl 0x" << hex << req << ": errno=" << dec << errno << " - ";
139 gLog << strerror(errno) << " (rc=" << rc << ")" << endl;
140 usleep(10);
141 continue;
142 }
143
144 if (!force)
145 {
146 gLog << err << "ERROR - MVideo::Ioctl 0x" << hex << req << ": errno=" << dec << errno << " - ";
147 gLog << strerror(errno) << " (rc=" << rc << ")" << endl;
148 }
149 return rc;
150 }
151 return -1;
152}
153
154// -------------------------------------------------------------
155//
156// Read the capabilities of the device
157//
158Bool_t MVideo::GetCapabilities()
159{
160 return Ioctl(VIDIOCGCAP, &fCaps)!=-1;
161}
162
163// -------------------------------------------------------------
164//
165// Read the properties of the device
166//
167Bool_t MVideo::GetProperties()
168{
169 return Ioctl(VIDIOCGPICT, &fProp)!=-1;
170}
171
172// -------------------------------------------------------------
173//
174// Read the video standard
175//
176Bool_t MVideo::GetVideoStandard()
177{
178 return Ioctl(VIDIOC_G_STD, &fVideoStandard)==-1;
179}
180
181// -------------------------------------------------------------
182//
183// Read the abilities of the tuner
184//
185Bool_t MVideo::GetTunerAbilities()
186{
187 fAbil.tuner = 0; // FIXME?
188 return Ioctl(VIDIOCGTUNER, &fAbil)!=-1;
189}
190
191// -------------------------------------------------------------
192//
193// Enumerate (get) all controls from the device and store them
194// as MVideoCtrl in fControls, starting with the id given as
195// argument.
196//
197Bool_t MVideo::EnumerateControls(UInt_t id)
198{
199 struct v4l2_queryctrl qctrl;
200 memset(&qctrl, 0, sizeof(qctrl));
201 qctrl.id = id;
202
203 while (1)
204 {
205 if (Ioctl(VIDIOC_QUERYCTRL, &qctrl, true, true)==-1)
206 break;
207
208 if (qctrl.maximum<=qctrl.minimum)
209 continue;
210
211 fControls.Add(new MVideoCtrl(qctrl));
212
213 qctrl.id++;
214 }
215
216 return kTRUE;
217}
218
219// -------------------------------------------------------------
220//
221// Enumerate (get) all basic and private controls from the
222// device and store them as MVideoCtrl in fControls.
223//
224Bool_t MVideo::EnumerateControls()
225{
226 if (!EnumerateControls(V4L2_CID_BASE))
227 return kFALSE;
228 if (!EnumerateControls(V4L2_CID_PRIVATE_BASE))
229 return kFALSE;
230
231 return kTRUE;
232}
233
234// -------------------------------------------------------------
235//
236// Reset a given control to it's default value as defined
237// by the device.
238//
239Bool_t MVideo::ResetControl(MVideoCtrl &vctrl) const
240{
241 return WriteControl(vctrl, vctrl.fDefault);
242}
243
244// -------------------------------------------------------------
245//
246// Reset all enumereated device controls to their default.
247// The default is defined by the device iteself.
248//
249Bool_t MVideo::ResetControls() const
250{
251 Bool_t rc = kTRUE;
252
253 TIter Next(&fControls);
254 MVideoCtrl *ctrl = 0;
255 while ((ctrl=((MVideoCtrl*)Next())))
256 if (!ResetControl(*ctrl))
257 {
258 gLog << err << "ERROR - Could not reset " << ctrl->fName << "." << endl;
259 rc = kFALSE;
260 }
261
262 return rc;
263}
264
265// -------------------------------------------------------------
266//
267// Read the value of the given control from the device
268// and store it back into the given MVideoCtrl.
269//
270Bool_t MVideo::ReadControl(MVideoCtrl &vctrl) const
271{
272 struct v4l2_control ctrl = { vctrl.fId, 0 };
273 if (Ioctl(VIDIOC_G_CTRL, &ctrl)==-1)
274 return kFALSE;
275
276 vctrl.fValue = ctrl.value;
277
278 return kTRUE;
279}
280
281// -------------------------------------------------------------
282//
283// Write the given value into the given control of the device.
284// On success the value is stored in the given MVideoCtrl.
285//
286Bool_t MVideo::WriteControl(MVideoCtrl &vctrl, Int_t val) const
287{
288 if (val<vctrl.fMinimum)
289 {
290 gLog << err << "ERROR - Value of " << val << " below minimum of " << vctrl.fMinimum << " for " << vctrl.fName << endl;
291 return kFALSE;
292 }
293
294 if (val>vctrl.fMaximum)
295 {
296 gLog << err << "ERROR - Value of " << val << " above maximum of " << vctrl.fMaximum << " for " << vctrl.fName << endl;
297 return kFALSE;
298 }
299
300 struct v4l2_control ctrl = { vctrl.fId, val };
301 if (Ioctl(VIDIOC_S_CTRL, &ctrl)==-1)
302 return kFALSE;
303
304 vctrl.fValue = val;
305
306 return kTRUE;
307}
308
309// -------------------------------------------------------------
310//
311// Set all controls from a TEnv. Note that all whitespaces
312// and colons in the control names (as defined by the name of
313// the MVideoCtrls stored in fControls) are replaced by
314// underscores.
315//
316Bool_t MVideo::SetControls(TEnv &env) const
317{
318 Bool_t rc = kTRUE;
319
320 TIter Next(&fControls);
321 TObject *o = 0;
322 while ((o=Next()))
323 {
324 if (!env.Defined(o->GetName()))
325 continue;
326
327 TString str = env.GetValue(o->GetName(), "");
328 str = str.Strip(TString::kBoth);
329 str.ReplaceAll(" ", "_");
330 str.ReplaceAll(":", "_");
331 if (str.IsNull())
332 continue;
333
334 MVideoCtrl &ctrl = *static_cast<MVideoCtrl*>(o);
335
336 const Int_t val = str=="default" || str=="def" ?
337 ctrl.fDefault : env.GetValue(o->GetName(), 0);
338
339 if (!WriteControl(ctrl, val))
340 rc = kFALSE;
341 }
342
343 return rc;
344}
345
346template<class S>
347Bool_t MVideo::Enumerate(vector<S> &vec, int request)
348{
349 for (int i=0; ; i++)
350 {
351 S input;
352 input.index = i;
353
354 const int rc = Ioctl(request, &input);
355 if (rc<0)
356 return kFALSE;
357 if (rc==1)
358 return kTRUE;
359
360 vec.push_back(input);
361 }
362
363 return kFALSE;
364}
365
366void MVideo::PrintInputs() const
367{
368 gLog << all;
369 for (vector<v4l2_input>::const_iterator it=fInputs.begin(); it!=fInputs.end(); it++)
370 {
371 gLog << "Input #" << it->index << endl;
372 gLog << " - " << it->name << endl;
373 gLog << " - " << (it->type==V4L2_INPUT_TYPE_CAMERA?"Camera":"Tuner") << endl;
374 gLog << " - TV Standard: " << hex << it->std << dec << endl;
375
376 gLog << " - Status: 0x" << hex << it->status;
377 if (it->status&V4L2_IN_ST_NO_POWER)
378 gLog << " NoPower";
379 if (it->status&V4L2_IN_ST_NO_SIGNAL)
380 gLog << " NoSignal";
381 if (it->status&V4L2_IN_ST_NO_COLOR)
382 gLog << " NoColor";
383 if (it->status&V4L2_IN_ST_NO_H_LOCK)
384 gLog << " NoHLock";
385 if (it->status&V4L2_IN_ST_COLOR_KILL)
386 gLog << " ColorKill";
387 gLog << endl;
388
389 /*
390 TV Standard
391 ===========
392 #define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001)
393 #define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002)
394 #define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004)
395 #define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008)
396 #define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010)
397 #define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020)
398 #define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040)
399 #define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080)
400
401 #define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100)
402 #define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200)
403 #define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400)
404 #define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800)
405 V4L2_STD_PAL_60 is a hybrid standard with 525 lines, 60 Hz refresh rate, and PAL color modulation with a 4.43 MHz color subcarrier. Some PAL video recorders can play back NTSC tapes in this mode for display on a 50/60 Hz agnostic PAL TV.
406
407 #define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000)
408 #define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000)
409 #define V4L2_STD_NTSC_443 ((v4l2_std_id)0x00004000)
410 V4L2_STD_NTSC_443 is a hybrid standard with 525 lines, 60 Hz refresh rate, and NTSC color modulation with a 4.43 MHz color subcarrier.
411
412 #define V4L2_STD_NTSC_M_KR ((v4l2_std_id)0x00008000)
413
414 #define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000)
415 #define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000)
416 #define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000)
417 #define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000)
418 #define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000)
419 #define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000)
420 #define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000)
421 #define V4L2_STD_SECAM_LC ((v4l2_std_id)0x00800000)
422
423
424 // ATSC/HDTV
425 #define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000)
426 #define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000)
427 V4L2_STD_ATSC_8_VSB and V4L2_STD_ATSC_16_VSB are U.S. terrestrial digital TV standards. Presently the V4L2 API does not support digital TV. See also the Linux DVB API at http://linuxtv.org.
428
429 #define V4L2_STD_PAL_BG (V4L2_STD_PAL_B | V4L2_STD_PAL_B1 | V4L2_STD_PAL_G)
430 #define V4L2_STD_B (V4L2_STD_PAL_B | V4L2_STD_PAL_B1 | V4L2_STD_SECAM_B)
431 #define V4L2_STD_GH (V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H)
432 #define V4L2_STD_PAL_DK (V4L2_STD_PAL_D | V4L2_STD_PAL_D1 | V4L2_STD_PAL_K)
433 #define V4L2_STD_PAL (V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_H | V4L2_STD_PAL_I)
434 #define V4L2_STD_NTSC (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_M_KR)
435 #define V4L2_STD_MN (V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | V4L2_STD_NTSC)
436 #define V4L2_STD_SECAM_DK (V4L2_STD_SECAM_D | V4L2_STD_SECAM_K | V4L2_STD_SECAM_K1)
437 #define V4L2_STD_DK (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK)
438 #define V4L2_STD_SECAM (V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H | V4L2_STD_SECAM_DK | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)
439 #define V4L2_STD_525_60 (V4L2_STD_PAL_M | V4L2_STD_PAL_60 | V4L2_STD_NTSC | V4L2_STD_NTSC_443)
440 #define V4L2_STD_625_50 (V4L2_STD_PAL | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | V4L2_STD_SECAM)
441 #define V4L2_STD_UNKNOWN 0
442 #define V4L2_STD_ALL (V4L2_STD_525_60 | V4L2_STD_625_50)
443 */
444
445 /*
446 Status:
447 =======
448 General
449 V4L2_IN_ST_NO_POWER 0x00000001 Attached device is off.
450 V4L2_IN_ST_NO_SIGNAL 0x00000002
451 V4L2_IN_ST_NO_COLOR 0x00000004 The hardware supports color decoding, but does not detect color modulation in the signal.
452
453 Analog Video
454 V4L2_IN_ST_NO_H_LOCK 0x00000100 No horizontal sync lock.
455 V4L2_IN_ST_COLOR_KILL 0x00000200 A color killer circuit automatically disables color decoding when it detects no color modulation. When this flag is set the color killer is enabled and has shut off color decoding.
456
457 Digital Video
458 V4L2_IN_ST_NO_SYNC 0x00010000 No synchronization lock.
459 V4L2_IN_ST_NO_EQU 0x00020000 No equalizer lock.
460 V4L2_IN_ST_NO_CARRIER 0x00040000 Carrier recovery failed.
461
462 VCR and Set-Top Box
463 V4L2_IN_ST_MACROVISION 0x01000000 Macrovision is an analog copy prevention system mangling the video signal to confuse video recorders. When this flag is set Macrovision has been detected.
464 V4L2_IN_ST_NO_ACCESS 0x02000000 Conditional access denied.
465 V4L2_IN_ST_VTR 0x04000000 VTR time constant. [?]
466 */
467 }
468}
469
470void MVideo::PrintStandards() const
471{
472 gLog << all;
473 for (vector<v4l2_standard>::const_iterator it=fStandards.begin(); it!=fStandards.end(); it++)
474 {
475 gLog << "Index #" << it->index << endl;
476 gLog << " - TV Standard: " << it->name << hex << "(" << it->id << ")" << dec << endl;
477 gLog << " - FPS: " << it->frameperiod.numerator << "/" << it->frameperiod.denominator << endl;
478 gLog << " - Lines: " << it->framelines << endl;
479 }
480}
481
482// -------------------------------------------------------------
483//
484// Open channel ch of the device
485//
486Bool_t MVideo::Open(Int_t ch)
487{
488 const Bool_t rc = Init(ch);
489 if (!rc)
490 Close();
491 return rc;
492}
493
494// -------------------------------------------------------------
495//
496// Open a channel of the device and retriev all necessary
497// informations from the driver. Initialize the shared
498// memory. Other access methods are not supported yet.
499//
500Bool_t MVideo::Init(Int_t channel)
501{
502 if (IsOpen())
503 {
504 gLog << warn << "WARNING - Device " << fPath << " already open." << endl;
505 return kTRUE;
506 }
507
508 gLog << all << "Opening " << fPath << "... " << flush;
509 do
510 {
511 fFileDesc = open(fPath, O_RDWR|O_NONBLOCK, 0);
512 usleep(1);
513 }
514 while (errno==19 && fFileDesc==-1);
515
516 if (fFileDesc == -1)
517 {
518 gLog << err << "ERROR: " << strerror(errno) << endl;
519 return kFALSE;
520 }
521
522 gLog << "done (" << fFileDesc << ")." << endl;
523
524 // Close device on exit
525 if (fcntl(fFileDesc, F_SETFD, FD_CLOEXEC)<0)
526 {
527 gLog << err << "ERROR - Call to fnctl (F_SETFD, FD_CLOEXEC) failed." << endl;
528 return kFALSE;
529 }
530
531
532
533/*
534 if (!Enumerate(fInputs, VIDIOC_ENUMINPUT))
535 {
536 gLog << err << "ERROR - Could not enumerate inputs." << endl;
537 return kFALSE;
538 }
539 PrintInputs();
540
541 if (!Enumerate(fStandards, VIDIOC_ENUMSTD))
542 {
543 gLog << err << "ERROR - Could not enumerate inputs." << endl;
544 return kFALSE;
545 }
546 PrintStandards();
547 */
548
549 int index = 3;
550 if (Ioctl(VIDIOC_S_INPUT, &index)==-1)
551 {
552 gLog << err << "ERROR - Could not set input." << endl;
553 return kFALSE;
554 }
555
556 //check the input
557 if (Ioctl(VIDIOC_G_INPUT, &index))
558 {
559 gLog << err << "ERROR - Could not get input." << endl;
560 return kFALSE;
561 }
562
563 v4l2_input input;
564 memset(&input, 0, sizeof (input));
565 input.index = index;
566 if (Ioctl(VIDIOC_ENUMINPUT, &input))
567 {
568 gLog << err << "ERROR - Could enum input." << endl;
569 return kFALSE;
570 }
571 gLog << "*** Input: " << input.name << " (" << input.index << ")" << endl;
572
573 v4l2_std_id st = 4;//standard.id;
574 if (Ioctl (VIDIOC_S_STD, &st))
575 {
576 gLog << err << "ERROR - Could not set standard." << endl;
577 return kFALSE;
578 }
579
580 v4l2_capability cap;
581 if (Ioctl(VIDIOC_QUERYCAP, &cap))
582 {
583 gLog << err << "ERROR - Could not get capabilities." << endl;
584 return kFALSE;
585 }
586
587 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
588 {
589 gLog << err << "ERROR - No capture capabaility." << endl;
590 return kFALSE;
591 }
592
593 v4l2_cropcap cropcap;
594 cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
595
596 if (Ioctl(VIDIOC_CROPCAP, &cropcap)==-1)
597 {
598 }
599
600 v4l2_crop crop;
601 crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
602 crop.c = cropcap.defrect; /* reset to default */
603
604 if (Ioctl(VIDIOC_S_CROP, &crop))
605 {
606 gLog << err << "Could not reset cropping." << endl;
607 return kFALSE;
608 }
609
610 v4l2_format fmt;
611 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
612 fmt.fmt.pix.width = 768;
613 fmt.fmt.pix.height = 576;
614 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
615
616 if (Ioctl(VIDIOC_S_FMT, &fmt)==-1)
617 {
618 gLog << err << "ERROR - Could not set format." << endl;
619 return kFALSE;
620 }
621 // The image format must be selected before buffers are allocated,
622 // with the VIDIOC_S_FMT ioctl. When no format is selected the driver
623 // may use the last, possibly by another application requested format.
624
625 v4l2_requestbuffers reqbuf;
626 memset (&reqbuf, 0, sizeof (reqbuf));
627
628 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
629 reqbuf.memory = V4L2_MEMORY_MMAP;
630 reqbuf.count = 4;//125;
631
632 if (Ioctl(VIDIOC_REQBUFS, &reqbuf)==-1)
633 {
634 gLog << err << "ERROR - Couldn't setup frame buffers." << endl;
635 return kFALSE;
636 }
637
638 gLog << all << "Allocated " << reqbuf.count << " frame buffers." << endl;
639
640 for (unsigned int i=0; i<reqbuf.count; i++)
641 {
642 v4l2_buffer buffer;
643 memset (&buffer, 0, sizeof (buffer));
644
645 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
646 buffer.memory = V4L2_MEMORY_MMAP;
647 buffer.index = i;
648
649 if (Ioctl(VIDIOC_QUERYBUF, &buffer))
650 {
651 gLog << err << "ERROR - Request of frame buffer " << i << " failed." << endl;
652 return kFALSE;
653 }
654
655 void *ptr = mmap(NULL, buffer.length,
656 PROT_READ | PROT_WRITE,
657 MAP_SHARED,
658 fFileDesc, buffer.m.offset);
659
660 if (MAP_FAILED == ptr)
661 {
662
663 gLog << err << "ERROR - Could not allocate shared memory." << endl;
664 return kFALSE;
665 // If you do not exit here you should unmap() and free()
666 // the buffers mapped so far.
667 //perror ("mmap");
668 //exit (EXIT_FAILURE);
669 }
670
671 fBuffers.push_back(make_pair(buffer, ptr));
672 }
673
674 return kTRUE;
675}
676
677Bool_t MVideo::Start()
678{
679 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
680 if (Ioctl(VIDIOC_STREAMON, &type)==-1)
681 {
682 gLog << err << "ERROR - Couldn't start capturing." << endl;
683 return kFALSE;
684 }
685
686 cout << "*** Stream on" << endl;
687
688 return kTRUE;
689}
690
691// -------------------------------------------------------------
692//
693// Close device. Free the shared memory
694//
695Int_t MVideo::Close()
696{
697 // if (!IsOpen())
698 // return kTRUE;
699/*
700 if (Ioctl(VIDIOC_STREAMON, &fBuffers[0])==-1)
701 {
702 gLog << err << "ERROR - Couldn't start capturing." << endl;
703 return kFALSE;
704 }
705*/
706 Bool_t rc = kTRUE;
707
708 gLog << all << "Closing " << fPath << " (" << fFileDesc << ")... " << flush;
709 if (fFileDesc != -1)
710 {
711 if (close(fFileDesc)<0)
712 {
713 gLog << err << "ERROR!" << endl;
714 rc = kFALSE;
715 }
716 fFileDesc = -1;
717 }
718 gLog << "done." << endl;
719
720 // unmap device memory
721 for (vector<pair<v4l2_buffer,void*> >::iterator it=fBuffers.begin(); it!=fBuffers.end(); it++)
722 {
723 munmap(it->second, it->first.length);
724 fBuffers.erase(it);
725 }
726
727 Reset();
728
729 return rc;
730}
731
732// -------------------------------------------------------------
733//
734// Instruct hardware to start capture into framebuffer frame
735//
736Bool_t MVideo::CaptureStart(unsigned int frame) const
737{
738 frame %= fBuffers.size();
739
740// cout << "*** CaptureStart " << frame << endl;
741
742 if (Ioctl(VIDIOC_QBUF, const_cast<v4l2_buffer*>(&fBuffers[frame].first))==-1)
743 {
744 gLog << err << "ERROR - Couldn't buffer " << frame << "." << endl;
745 return kFALSE;
746 }
747
748// cout << "*** " << errno << endl;
749
750 return kTRUE;
751
752 /*
753 struct video_mmap gb =
754 {
755 frame, // frame
756 fCaps.maxheight, fCaps.maxwidth, // height, width
757 VIDEO_PALETTE_RGB24 // palette
758 };
759
760#ifdef DEBUG
761 gLog << dbg << "CapturStart(" << frame << ")" << endl;
762#endif
763
764 //
765 // capture frame
766 //
767 if (Ioctl(VIDIOCMCAPTURE, &gb) != -1)
768 return kTRUE;
769
770// if (errno == EAGAIN)
771 gLog << err;
772 gLog << "ERROR - Couldn't start capturing frame " << frame << "." << endl;
773 gLog << " Maybe your card doesn't support VIDEO_PALETTE_RGB24." << endl;
774 return kFALSE;
775 */
776}
777
778// -------------------------------------------------------------
779//
780// Wait until hardware has finished capture into framebuffer frame
781//
782Int_t MVideo::CaptureWait(unsigned int frame, unsigned char **ptr) const
783{
784 frame %= fBuffers.size();
785
786 if (ptr)
787 *ptr = NULL;
788
789// const int SYNC_TIMEOUT = 1;
790
791//#ifdef DEBUG
792// cout << "*** CaptureWait " << frame << endl;
793//#endif
794
795 //alarm(SYNC_TIMEOUT);
796 const Int_t rc = Ioctl(VIDIOC_DQBUF, const_cast<v4l2_buffer*>(&fBuffers[frame].first), false);
797 if (rc==-4)
798 {
799 //cout << "ERROR - Waiting for frame " << frame << " timed out." << endl;
800 return kSKIP;
801 }
802 //alarm(0);
803
804 if (rc==-1)
805 {
806 gLog << err << "ERROR - Waiting for " << frame << " frame failed." << endl;
807 return kFALSE;
808 }
809
810 if (ptr)
811 *ptr = static_cast<unsigned char*>(fBuffers[frame].second);
812
813 return kTRUE;
814}
815
816// -------------------------------------------------------------
817//
818// Change the channel of a priviously opened device
819//
820Int_t MVideo::SetChannel(Int_t chan)
821{
822 return kSKIP;
823
824 if (fChannel.channel==chan)
825 return kSKIP;
826
827 if (chan<0 || chan>=fCaps.channels)
828 {
829 gLog << err << "ERROR - Set channel " << chan << " out of range." << endl;
830 return kFALSE;
831 }
832
833 // Switch to channel
834 struct video_channel ch = { chan, "", 0, 0, 0, 0 };
835 if (Ioctl(VIDIOCSCHAN, &ch)==-1)
836 {
837 gLog << err << "ERROR - Couldn't switch to channel " << chan << "." << endl;
838 gLog << " You might need a bttv version > 0.5.13" << endl;
839 return kFALSE;
840 }
841
842 // Get information about channel
843 if (Ioctl(VIDIOCGCHAN, &ch)==-1)
844 {
845 gLog << err << "ERROR - Getting information for channel " << chan << " failed." << endl;
846 return kFALSE;
847 }
848
849 memcpy(&fChannel, &ch, sizeof(fChannel));
850
851 gLog << all << "Switched to channel " << chan << endl;
852
853 return kTRUE;
854}
855
856// -------------------------------------------------------------
857//
858// Has the device capture capabilities?
859//
860Bool_t MVideo::CanCapture() const
861{
862 return fCaps.type&VID_TYPE_CAPTURE;
863}
864
865// -------------------------------------------------------------
866//
867// Has a tuner
868//
869Bool_t MVideo::HasTuner() const
870{
871 return fCaps.type&VID_TYPE_TUNER;
872}
873
874// -------------------------------------------------------------
875//
876// Returns the number of frame buffers which can be used
877//
878Int_t MVideo::GetNumBuffers() const
879{
880 return fBuffers.size();
881}
882
883// -------------------------------------------------------------
884//
885// Maximum width of the frame which can be captured
886//
887Int_t MVideo::GetWidth() const
888{
889 return 768;//fCaps.maxwidth;
890}
891
892// -------------------------------------------------------------
893//
894// Maximum height of the frame which can be captured
895//
896Int_t MVideo::GetHeight() const
897{
898 return 576;//fCaps.maxheight;
899}
900
901// -------------------------------------------------------------
902//
903// Return the device type as string
904//
905TString MVideo::GetDevType(int type) const
906{
907 TString rc;
908 if (CanCapture())
909 rc += " capture";
910 if (HasTuner())
911 rc += " tuner";
912 if (type&VID_TYPE_TELETEXT)
913 rc += " teletext";
914 if (type&VID_TYPE_OVERLAY)
915 rc += " overlay";
916 if (type&VID_TYPE_CHROMAKEY)
917 rc += " chromakey";
918 if (type&VID_TYPE_CLIPPING)
919 rc += " clipping";
920 if (type&VID_TYPE_FRAMERAM)
921 rc += " frameram";
922 if (type&VID_TYPE_SCALES)
923 rc += " scales";
924 if (type&VID_TYPE_MONOCHROME)
925 rc += " monochrom";
926 if (type&VID_TYPE_SUBCAPTURE)
927 rc += " subcapature";
928 return rc;
929}
930
931TString MVideo::GetTunerFlags(Int_t flags) const
932{
933 TString rc;
934 if (flags&VIDEO_TUNER_PAL)
935 rc += " PAL";
936 if (flags&VIDEO_TUNER_NTSC)
937 rc += " NTSC";
938 if (flags&VIDEO_TUNER_SECAM)
939 rc += " SECAM";
940 if (flags&VIDEO_TUNER_LOW)
941 rc += " kHz";
942 if (flags&VIDEO_TUNER_NORM)
943 rc += " CanSetNorm";
944 if (flags&VIDEO_TUNER_STEREO_ON)
945 rc += " StereoOn";
946 return rc;
947}
948
949TString MVideo::GetTunerMode(Int_t mode) const
950{
951 switch (mode)
952 {
953 case VIDEO_MODE_PAL:
954 return "PAL";
955 case VIDEO_MODE_NTSC:
956 return "NTSC";
957 case VIDEO_MODE_SECAM:
958 return "SECAM";
959 case VIDEO_MODE_AUTO:
960 return "AUTO";
961 }
962 return "undefined";
963}
964
965// -------------------------------------------------------------
966//
967// Return the channel flags as string
968//
969TString MVideo::GetChannelFlags(Int_t flags) const
970{
971 TString rc = "video";
972 if (flags&VIDEO_VC_TUNER)
973 rc += " tuner";
974 if (flags&VIDEO_VC_AUDIO)
975 rc += " audio";
976// if (flags&VIDEO_VC_NORM)
977// rc += " normsetting";
978 return rc;
979}
980
981// -------------------------------------------------------------
982//
983// Return the channel type as string
984//
985TString MVideo::GetChannelType(Int_t type) const
986{
987 if (type&VIDEO_TYPE_TV)
988 return "TV";
989 if (type&VIDEO_TYPE_CAMERA)
990 return "Camera";
991 return "unknown";
992}
993
994// -------------------------------------------------------------
995//
996// Return the palette pal as string
997//
998TString MVideo::GetPalette(Int_t pal) const
999{
1000 switch (pal)
1001 {
1002 case VIDEO_PALETTE_GREY:
1003 return "VIDEO_PALETTE_GREY: Linear intensity grey scale";
1004 case VIDEO_PALETTE_HI240:
1005 return "VIDEO_PALETTE_HI240: BT848 8-bit color cube";
1006 case VIDEO_PALETTE_RGB565:
1007 return "VIDEO_PALETTE_RGB565: RGB565 packed into 16-bit words";
1008 case VIDEO_PALETTE_RGB555:
1009 return "VIDEO_PALETTE_RGB555: RGB555 packed into 16-bit words, top bit undefined";
1010 case VIDEO_PALETTE_RGB24:
1011 return "VIDEO_PALETTE_RGB24: RGB888 packed into 24-bit words";
1012 case VIDEO_PALETTE_RGB32:
1013 return "VIDEO_PALETTE_RGB32: RGB888 packed into the low three bytes of 32-bit words. Top bits undefined.";
1014 case VIDEO_PALETTE_YUV422:
1015 return "VIDEO_PALETTE_YUV422: Video style YUV422 - 8-bit packed, 4-bit Y, 2-bits U, 2-bits V";
1016 case VIDEO_PALETTE_YUYV:
1017 return "VIDEO_PALETTE_YUYV: YUYV";
1018 case VIDEO_PALETTE_UYVY:
1019 return "VIDEO_PALETTE_UYVY: UYVY";
1020 case VIDEO_PALETTE_YUV420:
1021 return "VIDEO_PALETTE_YUV420: YUV420";
1022 case VIDEO_PALETTE_YUV411:
1023 return "VIDEO_PALETTE_YUV411: YUV411";
1024 case VIDEO_PALETTE_RAW:
1025 return "VIDEO_PALETTE_RAW: Raw capture (Bt848)";
1026 case VIDEO_PALETTE_YUV422P:
1027 return "VIDEO_PALETTE_YUV422P: YUV 4:2:2 planar";
1028 case VIDEO_PALETTE_YUV411P:
1029 return "VIDEO_PALETTE_YUV411P: YUV 4:1:1 planar";
1030 }
1031 return "unknown";
1032}
1033
1034// -------------------------------------------------------------
1035//
1036// Print informations about the device, the capabilities, the
1037// channel and all available information
1038//
1039void MVideo::Print() const
1040{
1041 gLog << all << dec;
1042
1043 gLog << "Device " << fPath << " " << (fFileDesc>0?"open":"closed") << "." << endl;
1044
1045 if (fFileDesc<=0)
1046 return;
1047
1048 gLog << " - Name: " << fCaps.name << endl;
1049 gLog << " - DevType: " << GetDevType(fCaps.type) << endl;
1050 gLog << " - Channels: " << fCaps.channels << endl;
1051 gLog << " - Audios: " << fCaps.audios << endl;
1052 gLog << " - Size: ";
1053 gLog << fCaps.minwidth << "x" << fCaps.minheight << " to ";
1054 gLog << fCaps.maxwidth << "x" << fCaps.maxheight << endl;
1055 gLog << endl;
1056 if (fChannel.channel>=0)
1057 {
1058 gLog << " - Channel: " << fChannel.channel << " (" << fChannel.name << ")" << endl;
1059 gLog << " - IsA: " << GetChannelType(fChannel.type) << " with " << GetChannelFlags(fChannel.flags) << " (" << fChannel.flags << ")" << endl;
1060 //if (fChannel.flags&VIDEO_VC_NORM)
1061 gLog << " - Norm: " << fChannel.norm << endl;
1062 gLog << endl;
1063 }
1064
1065 if (fAbil.tuner>=0)
1066 {
1067 gLog << " - Tuner: " << fAbil.tuner << endl;
1068 gLog << " - Name: " << fAbil.name << endl;
1069 // gLog << " - Tuner Range: " << fAbil.rangelow << " - " << fAbil.rangehigh << endl;
1070 gLog << " - Tuner flags: " << GetTunerFlags(fAbil.flags) << " (" << fAbil.flags << ")" << endl;
1071 gLog << " - Tuner mode: " << GetTunerMode(fAbil.mode) << " (" << fAbil.mode << ")" <<endl;
1072 gLog << " - Signal Strength: " << fAbil.signal << endl;
1073 }
1074
1075 gLog << " - Brightness: " << fProp.brightness << endl;
1076 gLog << " - Hue: " << fProp.hue << endl;
1077 gLog << " - Color: " << fProp.colour << endl;
1078 gLog << " - Contrast: " << fProp.contrast << endl;
1079 gLog << " - Whiteness: " << fProp.whiteness << endl;
1080 gLog << " - Depth: " << fProp.depth << endl;
1081 gLog << " - Palette: " << GetPalette(fProp.palette) << " (" << fProp.palette << ")" << endl;
1082 gLog << endl;
1083
1084// gLog << " - BufferSize: 0x" << hex << fBuffer.size << " (" << dec << fBuffer.frames << " frames)" << endl;
1085// gLog << " - Offsets: " << hex;
1086// for (int i=0; i<fBuffer.frames; i++)
1087// gLog << " 0x" << fBuffer.offsets[i];
1088// gLog << dec << endl;
1089
1090 gLog << inf2 << "Controls:" << endl;
1091 fControls.Print();
1092}
1093
1094/*
1095void MVideo::SetPicPar(int bright, int hue, int contrast)
1096{
1097 struct video_picture pict;
1098
1099 Ioctl(VIDIOCGPICT, &pict); // get
1100
1101 if (contrast != -1)
1102 pict.contrast = contrast;
1103
1104 if (bright != -1)
1105 pict.brightness = bright;
1106
1107 if (hue != -1)
1108 pict.hue = hue;
1109
1110 Ioctl(VIDIOCSPICT, &pict); //set
1111}
1112
1113void MVideo::GetPicPar(int *bright, int *hue, int *contrast)
1114{
1115 struct video_picture pict;
1116
1117 Ioctl(VIDIOCGPICT, &pict); // get
1118
1119 *contrast = pict.contrast;
1120 *bright = pict.brightness;
1121 *hue = pict.hue;
1122}
1123*/
Note: See TracBrowser for help on using the repository browser.