Fawkes API  Fawkes Development Version
v4l1.cpp
1 
2 /***************************************************************************
3  * v4l1.cpp - Implementation to access V4L cam
4  *
5  * Generated: Fri Mar 11 17:48:27 2005
6  * Copyright 2005 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <core/exception.h>
25 #include <core/exceptions/software.h>
26 #include <fvcams/v4l1.h>
27 #include <fvutils/color/colorspaces.h>
28 #include <fvutils/color/rgb.h>
29 #include <fvutils/system/camargp.h>
30 #include <linux/types.h>
31 #include <linux/videodev.h>
32 #include <sys/ioctl.h>
33 #include <sys/mman.h>
34 #include <sys/stat.h>
35 #include <sys/time.h> /* gettimeofday() */
36 #include <sys/types.h>
37 
38 #include <cassert>
39 #include <cstdio>
40 #include <cstdlib>
41 #include <cstring>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <iostream>
45 #include <unistd.h>
46 
47 using namespace std;
48 using namespace fawkes;
49 
50 namespace firevision {
51 
52 /// @cond INTERNALS
53 
54 class V4L1CameraData
55 {
56 public:
57  V4L1CameraData(const char *device_name)
58  {
59  this->device_name = strdup(device_name);
60  }
61 
62  ~V4L1CameraData()
63  {
64  free(device_name);
65  }
66 
67 public:
68  char *device_name;
69 
70  /* V4L1 stuff */
71  struct video_capability capabilities; // Device Capabilities: Can overlay, Number of channels, etc
72  struct video_buffer vbuffer; // information about buffer
73  struct video_window window; // Window Information: Size, Depth, etc
74  struct video_channel
75  *channel; // Channels information: Channel[0] holds information for channel 0 and so on...
76  struct video_picture picture; // Picture information: Palette, contrast, hue, etc
77  struct video_tuner * tuner; // Tuner Information: if the card has tuners...
78  struct video_audio audio; // If the card has audio
79  struct video_mbuf
80  captured_frame_buffer; // Information for the frame to be captured: norm, palette, etc
81  struct video_mmap *buf_v4l; // mmap() buffer VIDIOCMCAPTURE
82 };
83 
84 /// @endcond
85 
86 /** @class V4L1Camera <fvcams/v4l1.h>
87  * Video4Linux 1 camera implementation.
88  */
89 
90 /** Constructor.
91  * @param device_name device file name (e.g. /dev/video0)
92  */
93 V4L1Camera::V4L1Camera(const char *device_name)
94 {
95  started = opened = false;
96  data_ = new V4L1CameraData(device_name);
97 }
98 
99 /** Constructor.
100  * Initialize camera with parameters from camera argument parser.
101  * Supported arguments:
102  * - device=DEV, device file, for example /dev/video0
103  * @param cap camera argument parser
104  */
105 V4L1Camera::V4L1Camera(const CameraArgumentParser *cap)
106 {
107  started = opened = false;
108  if (cap->has("device")) {
109  data_ = new V4L1CameraData(cap->get("device").c_str());
110  } else {
111  throw MissingParameterException("Missing device for V4L1Camera");
112  }
113 }
114 
115 /** Protected Constructor.
116  * Gets called from V4LCamera, when the device has already been opened
117  * and determined to be a V4L1 device.
118  * @param device_name device file name (e.g. /dev/video0)
119  * @param dev file descriptor of the opened device
120  */
121 V4L1Camera::V4L1Camera(const char *device_name, int dev)
122 {
123  started = opened = false;
124  data_ = new V4L1CameraData(device_name);
125  this->dev = dev;
126 
127  // getting grabber info in capabilities struct
128  if ((ioctl(dev, VIDIOCGCAP, &(data_->capabilities))) == -1) {
129  throw Exception("V4L1Cam: Could not get capabilities");
130  }
131 
132  post_open();
133 }
134 
135 /** Destructor. */
136 V4L1Camera::~V4L1Camera()
137 {
138  delete data_;
139 }
140 
141 void
142 V4L1Camera::open()
143 {
144  opened = false;
145 
146  dev = ::open(data_->device_name, O_RDWR);
147  if (dev < 0) {
148  throw Exception("V4L1Cam: Could not open device");
149  }
150 
151  // getting grabber info in capabilities struct
152  if ((ioctl(dev, VIDIOCGCAP, &(data_->capabilities))) == -1) {
153  throw Exception("V4L1Cam: Could not get capabilities");
154  }
155 
156  post_open();
157 }
158 
159 /**
160  * Post-open() operations
161  * @param dev file descriptor of the opened device
162  */
163 void
164 V4L1Camera::post_open()
165 {
166  // Capture window information
167  if ((ioctl(dev, VIDIOCGWIN, &data_->window)) == -1) {
168  throw Exception("V4L1Cam: Could not get window information");
169  }
170 
171  // Picture information
172  if ((ioctl(dev, VIDIOCGPICT, &data_->picture)) == -1) {
173  throw Exception("V4L1Cam: Could not get window information");
174  }
175 
176  ///Video Channel Information or Video Sources
177  ///Allocate space for each channel
178  data_->channel = (struct video_channel *)malloc(sizeof(struct video_channel)
179  * (data_->capabilities.channels + 1));
180  for (int ch = 0; ch < data_->capabilities.channels; ch++) {
181  data_->channel[ch].norm = 0;
182  if ((ioctl(dev, VIDIOCSCHAN, &data_->channel[ch])) == -1) {
183  printf("V4L1Cam: Could not get channel information for channel %i: %s", ch, strerror(errno));
184  }
185  }
186 
187  ///Trying to capture through read()
188  if (ioctl(dev, VIDIOCGMBUF, data_->captured_frame_buffer) == -1) {
189  capture_method = READ;
190  frame_buffer =
191  (unsigned char *)malloc(data_->window.width * data_->window.height * RGB_PIXEL_SIZE);
192  } else {
193  capture_method = MMAP;
194  frame_buffer = (unsigned char *)
195  mmap(0, data_->captured_frame_buffer.size, PROT_READ | PROT_WRITE, MAP_SHARED, dev, 0);
196  if ((unsigned char *)-1 == (unsigned char *)frame_buffer) {
197  throw Exception("V4L1Cam: Cannot initialize mmap region");
198  }
199  }
200 
201  data_->buf_v4l = NULL;
202 
203  opened = true;
204 }
205 
206 void
207 V4L1Camera::start()
208 {
209  started = false;
210  if (!opened) {
211  throw Exception("V4L1Cam: Trying to start closed cam!");
212  }
213 
214  started = true;
215 }
216 
217 void
218 V4L1Camera::stop()
219 {
220  started = false;
221 }
222 
223 void
224 V4L1Camera::print_info()
225 {
226  if (!opened)
227  return;
228 
229  cout << endl
230  << "CAPABILITIES" << endl
231  << "===========================================================================" << endl;
232 
233  if (data_->capabilities.type & VID_TYPE_CAPTURE)
234  cout << " + Can capture to memory" << endl;
235  if (data_->capabilities.type & VID_TYPE_TUNER)
236  cout << " + Has a tuner of some form" << endl;
237  if (data_->capabilities.type & VID_TYPE_TELETEXT)
238  cout << " + Has teletext capability" << endl;
239  if (data_->capabilities.type & VID_TYPE_OVERLAY)
240  cout << " + Can overlay its image onto the frame buffer" << endl;
241  if (data_->capabilities.type & VID_TYPE_CHROMAKEY)
242  cout << " + Overlay is Chromakeyed" << endl;
243  if (data_->capabilities.type & VID_TYPE_CLIPPING)
244  cout << " + Overlay clipping is supported" << endl;
245  if (data_->capabilities.type & VID_TYPE_FRAMERAM)
246  cout << " + Overlay overwrites frame buffer memory" << endl;
247  if (data_->capabilities.type & VID_TYPE_SCALES)
248  cout << " + The hardware supports image scaling" << endl;
249  if (data_->capabilities.type & VID_TYPE_MONOCHROME)
250  cout << " + Image capture is grey scale only" << endl;
251  if (data_->capabilities.type & VID_TYPE_SUBCAPTURE)
252  cout << " + Can subcapture" << endl;
253 
254  cout << endl;
255  cout << " Number of Channels ='" << data_->capabilities.channels << "'" << endl;
256  cout << " Number of Audio Devices ='" << data_->capabilities.audios << "'" << endl;
257  cout << " Maximum Capture Width ='" << data_->capabilities.maxwidth << "'" << endl;
258  cout << " Maximum Capture Height ='" << data_->capabilities.maxheight << "'" << endl;
259  cout << " Minimum Capture Width ='" << data_->capabilities.minwidth << "'" << endl;
260  cout << " Minimum Capture Height ='" << data_->capabilities.minheight << "'" << endl;
261 
262  cout << endl
263  << "CAPTURE WINDOW INFO" << endl
264  << "===========================================================================" << endl;
265 
266  cout << " X Coord in X window Format: " << data_->window.x << endl;
267  cout << " Y Coord in X window Format: " << data_->window.y << endl;
268  cout << " Width of the Image Capture: " << data_->window.width << endl;
269  cout << " Height of the Image Capture: " << data_->window.height << endl;
270  cout << " ChromaKey: " << data_->window.chromakey << endl;
271 
272  cout << endl
273  << "DEVICE PICTURE INFO" << endl
274  << "===========================================================================" << endl;
275 
276  cout << " Picture Brightness: " << data_->picture.brightness << endl;
277  cout << " Picture Hue: " << data_->picture.hue << endl;
278  cout << " Picture Colour: " << data_->picture.colour << endl;
279  cout << " Picture Contrast: " << data_->picture.contrast << endl;
280  cout << " Picture Whiteness: " << data_->picture.whiteness << endl;
281  cout << " Picture Depth: " << data_->picture.depth << endl;
282  cout << " Picture Palette: " << data_->picture.palette << " (";
283 
284  if (data_->picture.palette == VIDEO_PALETTE_GREY)
285  cout << "VIDEO_PALETTE_GRAY";
286  if (data_->picture.palette == VIDEO_PALETTE_HI240)
287  cout << "VIDEO_PALETTE_HI240";
288  if (data_->picture.palette == VIDEO_PALETTE_RGB565)
289  cout << "VIDEO_PALETTE_RGB565";
290  if (data_->picture.palette == VIDEO_PALETTE_RGB555)
291  cout << "VIDEO_PALETTE_RGB555";
292  if (data_->picture.palette == VIDEO_PALETTE_RGB24)
293  cout << "VIDEO_PALETTE_RGB24";
294  if (data_->picture.palette == VIDEO_PALETTE_RGB32)
295  cout << "VIDEO_PALETTE_RGB32";
296  if (data_->picture.palette == VIDEO_PALETTE_YUV422)
297  cout << "VIDEO_PALETTE_YUV422";
298  if (data_->picture.palette == VIDEO_PALETTE_YUYV)
299  cout << "VIDEO_PALETTE_YUYV";
300  if (data_->picture.palette == VIDEO_PALETTE_UYVY)
301  cout << "VIDEO_PALETTE_UYVY";
302  if (data_->picture.palette == VIDEO_PALETTE_YUV420)
303  cout << "VIDEO_PALETTE_YUV420";
304  if (data_->picture.palette == VIDEO_PALETTE_YUV411)
305  cout << "VIDEO_PALETTE_YUV411";
306  if (data_->picture.palette == VIDEO_PALETTE_RAW)
307  cout << "VIDEO_PALETTE_RAW";
308  if (data_->picture.palette == VIDEO_PALETTE_YUV422P)
309  cout << "VIDEO_PALETTE_YUV422P";
310  if (data_->picture.palette == VIDEO_PALETTE_YUV411P)
311  cout << "VIDEO_PALETTE_YUV411P";
312 
313  cout << ")" << endl;
314 
315  cout << endl
316  << "VIDEO SOURCE INFO" << endl
317  << "===========================================================================" << endl;
318 
319  cout << " Channel Number or Video Source Number: " << data_->channel->channel << endl;
320  cout << " Channel Name: " << data_->channel->name << endl;
321  cout << " Number of Tuners for this source: " << data_->channel->tuners << endl;
322  cout << " Channel Norm: " << data_->channel->norm << endl;
323  if (data_->channel->flags & VIDEO_VC_TUNER)
324  cout << " + This channel source has tuners" << endl;
325  if (data_->channel->flags & VIDEO_VC_AUDIO)
326  cout << " + This channel source has audio" << endl;
327  if (data_->channel->type & VIDEO_TYPE_TV)
328  cout << " + This channel source is a TV input" << endl;
329  if (data_->channel->type & VIDEO_TYPE_CAMERA)
330  cout << " + This channel source is a Camera input" << endl;
331 
332  cout << endl
333  << "FRAME BUFFER INFO" << endl
334  << "===========================================================================" << endl;
335 
336  cout << " Base Physical Address: " << data_->vbuffer.base << endl;
337  cout << " Height of Frame Buffer: " << data_->vbuffer.height << endl;
338  cout << " Width of Frame Buffer: " << data_->vbuffer.width << endl;
339  cout << " Depth of Frame Buffer: " << data_->vbuffer.depth << endl;
340  cout << " Bytes Per Line: " << data_->vbuffer.bytesperline << endl;
341 
342  /* Which channel!?
343  cout << endl << "CHANNEL INFO" << endl
344  << "===========================================================================" << endl;
345 
346  cout << " Channel: " << ch << " - " << channel[ch].name << endl;
347  cout << " Number of Tuners: " << channel[0].tuners << endl;
348  cout << " Input Type: " << channel[ch].type << endl;
349  cout << " Flags: " << endl;
350  if(channel[0].flags & VIDEO_VC_TUNER)
351  cout << " + This Channel Source has Tuners" << endl;
352  if(channel[0].flags & VIDEO_VC_AUDIO)
353  cout << " + This Channel Source has Audio" << endl;
354  // if(channel[0].flags & VIDEO_VC_NORM)
355  //cout << " \tThis Channel Source has Norm\n");
356  cout << " Norm for Channel: '" << channel[0].norm << "'" << endl;
357  */
358 }
359 
360 void
361 V4L1Camera::capture()
362 {
363  if (capture_method == READ) {
364  int len = read(dev, frame_buffer, data_->window.width * data_->window.height * RGB_PIXEL_SIZE);
365  if (len < 0) {
366  throw Exception("V4L1Cam: Could not capture frame");
367  }
368  } else {
369  data_->buf_v4l =
370  (struct video_mmap *)malloc(data_->captured_frame_buffer.frames * sizeof(struct video_mmap));
371 
372  ///Setting up the palette, size of frame and which frame to capture
373  data_->buf_v4l[0].format = data_->picture.palette;
374  data_->buf_v4l[0].frame = 0;
375  data_->buf_v4l[0].width = data_->window.width;
376  data_->buf_v4l[0].height = data_->window.height;
377 
378  if (ioctl(dev, VIDIOCMCAPTURE, &(data_->buf_v4l[0])) == -1) {
379  throw Exception("V4L1Cam: Could not capture frame (VIDIOCMCAPTURE)");
380  }
381  ///Waiting for the frame to finish
382  int Frame = 0;
383  if (ioctl(dev, VIDIOCSYNC, &Frame) == -1) {
384  throw Exception("V4L1Cam: Could not capture frame (VIDIOCSYNC)");
385  }
386  }
387 }
388 
389 void
390 V4L1Camera::dispose_buffer()
391 {
392  if (capture_method == MMAP) {
393  if (data_->buf_v4l != NULL) {
394  free(data_->buf_v4l);
395  data_->buf_v4l = NULL;
396  }
397  munmap(frame_buffer, data_->captured_frame_buffer.size);
398  }
399 }
400 
401 unsigned char *
402 V4L1Camera::buffer()
403 {
404  return frame_buffer;
405 }
406 
407 unsigned int
408 V4L1Camera::buffer_size()
409 {
410  return colorspace_buffer_size(RGB, data_->window.width, data_->window.height);
411 }
412 
413 void
414 V4L1Camera::close()
415 {
416  if (opened) {
417  ::close(dev);
418  }
419 }
420 
421 unsigned int
422 V4L1Camera::pixel_width()
423 {
424  if (opened) {
425  return data_->window.width;
426  } else {
427  throw Exception("V4L1Cam::pixel_width(): Camera not opened");
428  }
429 }
430 
431 unsigned int
432 V4L1Camera::pixel_height()
433 {
434  if (opened) {
435  return data_->window.height;
436  } else {
437  throw Exception("V4L1Cam::pixel_height(): Camera not opened");
438  }
439 }
440 
441 colorspace_t
442 V4L1Camera::colorspace()
443 {
444  return BGR;
445 }
446 
447 void
448 V4L1Camera::flush()
449 {
450 }
451 
452 bool
453 V4L1Camera::ready()
454 {
455  return started;
456 }
457 
458 void
459 V4L1Camera::set_image_number(unsigned int n)
460 {
461 }
462 
463 } // end namespace firevision
fawkes
firevision::CameraArgumentParser::has
bool has(std::string s) const
Check if an parameter was given.
Definition: camargp.cpp:144
fawkes::MissingParameterException
Definition: software.h:77
firevision::CameraArgumentParser
Definition: camargp.h:39
firevision::CameraArgumentParser::get
std::string get(std::string s) const
Get the value of the given parameter.
Definition: camargp.cpp:155
fawkes::Exception
Definition: exception.h:39