~jaromil/freej/master

« back to all changes in this revision

Viewing changes to src/v4l2_layer.cpp

  • Committer: fred
  • Date: 2011-04-22 23:45:46 UTC
  • mto: This revision was merged to the branch mainline in revision 1552.
  • Revision ID: git-v1:9be6947d00722cabfcb779eca527e25a692f3258
Added the ability to change the V4L2 devices resolution

- Created a QqComboRes class.

- In Layer class, added the types VIDEOLAYER and V4L2LAYER.

- In v4l2_layer.h and .cpp, created a Res class containing the
available resolutions.

- In QqWidget conctructor, determines if the layer is a v4l2 layer,
added a combobox with the different resolutions if it is.

- In a Qfreej menu, added the full screen function.

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
 
41
41
#include <v4l2_layer.h>
42
42
 
 
43
#define ARRAY_RESOLUTION_SIZE 30
 
44
 
43
45
FACTORY_REGISTER_INSTANTIATOR(Layer, V4L2CamLayer, CamLayer, v4l2);
44
46
 
 
47
Res::Res(int sz) {
 
48
  m_size = sz;
 
49
  m_sizes = (int(*)[2]) malloc(sz * sizeof(*m_sizes));
 
50
  m_idx = 0;
 
51
  m_curIdx = 0;
 
52
}
 
53
 
 
54
Res::~Res() {
 
55
  if(m_sizes) free(m_sizes);
 
56
}
 
57
 
 
58
bool Res::addRes(int x, int y, int type) {
 
59
  if (type == V4L2_FRMSIZE_TYPE_DISCRETE) {
 
60
    if (m_idx < (m_size -1)) {
 
61
      m_sizes[m_idx][0] = x;
 
62
      m_sizes[m_idx][1] = y;
 
63
      std::cerr << "--" << m_sizes[m_idx][0] << "x" << y << std::endl;
 
64
      m_idx++;
 
65
      return (true);
 
66
    }
 
67
    else
 
68
      return (false);
 
69
  }
 
70
/*  else {
 
71
    if (m_idx > 0) {
 
72
      m_sizes[m_idx][0] = x;
 
73
      m_sizes[m_idx][1] = y;
 
74
      m_idx--;
 
75
      return (true);
 
76
    }
 
77
    else
 
78
      return (false);
 
79
  }*/
 
80
}
 
81
 
 
82
int Res::getNb() {
 
83
  return (m_idx);
 
84
}
 
85
 
 
86
int Res::getX(int val) {
 
87
  if ((val < m_idx) && (val >= 0))
 
88
    return (m_sizes[val][0]);
 
89
  else {
 
90
    return (0);
 
91
  }
 
92
}
 
93
 
 
94
int Res::getY(int val) {
 
95
  if ((val < m_idx) && (val >= 0))
 
96
    return (m_sizes[val][1]);
 
97
  else {
 
98
    return (0);
 
99
  }
 
100
}
 
101
 
 
102
void Res::setsX(int x) {
 
103
  for (int i; i < m_idx; i++) {
 
104
    if (x == m_sizes[i][0]) {
 
105
      m_curIdx = i;
 
106
      break;
 
107
    }
 
108
  }
 
109
}
 
110
 
 
111
int Res::getCurIdx() {
 
112
  return (m_curIdx);
 
113
}
 
114
 
 
115
void Res::chgRes(int line) {
 
116
  if (line < m_idx) {
 
117
    // first, turn off streaming
 
118
/*    if(-1 == ioctl(m_fd, VIDIOC_STREAMOFF, &buftype)) {
 
119
      error("VIDIOC_STREAMOFF: %s", errno);
 
120
    }
 
121
  */
 
122
  
 
123
  /* Cleanup. */
 
124
/*  for (unsigned int i = 0; i < reqbuf.count; i++)
 
125
    munmap (buffers[i].start, buffers[i].length);
 
126
    memset (&m_format, 0, sizeof (m_format));
 
127
    m_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
128
 
 
129
    if (-1 == ioctl (m_fd, VIDIOC_G_FMT, &m_format)) {
 
130
      perror ("VIDIOC_G_FMT");
 
131
      return;
 
132
    }*/
 
133
//     memset (&m_format, 0, sizeof (m_format));
 
134
//     m_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
135
/*    m_format.fmt.pix.width = m_sizes[line][0];
 
136
    m_format.fmt.pix.height = m_sizes[line][1];
 
137
    m_format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
 
138
    m_format.fmt.pix.field = V4L2_FIELD_ANY;
 
139
    if(0 == ioctl(m_fd, VIDIOC_TRY_FMT, &m_format)) {
 
140
      std::cerr << "--- we should be able to setup the resolution :)" << std::endl;
 
141
      if(-1 == ioctl(m_fd, VIDIOC_S_FMT, &m_format)) {
 
142
        error("VIDIOC_G_FMT: %s", strerror(errno));
 
143
        return;
 
144
      }
 
145
    }*/
 
146
  }
 
147
}
 
148
 
45
149
V4L2CamLayer::V4L2CamLayer() 
46
150
  :Layer() {
47
151
 
51
155
  fd = 0;
52
156
  frame = NULL;
53
157
  buffers = NULL;
54
 
 
 
158
  nb_sizes = 0;
 
159
  m_res = NULL;
55
160
  set_name("V4L2");
56
161
}
57
162
 
58
163
V4L2CamLayer::~V4L2CamLayer() {
59
 
 
 
164
  if(m_res) delete(m_res);
60
165
  if(fd) ::close(fd);
61
166
  if(buffers) ::free(buffers);
62
167
  if(frame) ::free(frame);
72
177
    fd = ::open(devfile,O_RDWR);
73
178
  }
74
179
  notice("Video4Linux2 device opened: %s",devfile);
 
180
  
 
181
  strcpy (m_devfile, devfile);
75
182
  // Check that streaming is supported
76
183
  
77
184
  memset(&capability, 0, sizeof(capability));
112
219
    standard.index++;
113
220
  }
114
221
 
115
 
  //displays the format description
 
222
  //fills the frame size the format description
116
223
  memset (&fmtdesc, 0, sizeof (fmtdesc));
117
224
  fmtdesc.index = 0;
118
225
  fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
119
226
  while (0 == ioctl (fd, VIDIOC_ENUM_FMT, &fmtdesc)) {
120
227
    std::cerr << "----- format description :" << fmtdesc.description << std::endl;
 
228
    if (!m_res)
 
229
      m_res = new Res (ARRAY_RESOLUTION_SIZE);
 
230
    for (int i=0; ;i++){
 
231
      memset(&framesize, 0, sizeof framesize);
 
232
      framesize.pixel_format = fmtdesc.pixelformat;
 
233
      framesize.index = i;
 
234
      int ret = ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &framesize);
 
235
      if (ret < 0)
 
236
        break;
 
237
      if (i != framesize.index)
 
238
        error ("Warning: driver returned wrong frame index "
 
239
                                "%u.\n", framesize.index);
 
240
      if (fmtdesc.pixelformat != framesize.pixel_format)
 
241
        error("Warning: driver returned wrong frame pixel "
 
242
                                "format %08x.\n", framesize.pixel_format);
 
243
 
 
244
      switch (framesize.type) {
 
245
        case V4L2_FRMSIZE_TYPE_DISCRETE:
 
246
          m_res->addRes (framesize.discrete.width, framesize.discrete.height, V4L2_FRMSIZE_TYPE_DISCRETE);
 
247
          break;
 
248
 
 
249
        case V4L2_FRMSIZE_TYPE_CONTINUOUS:
 
250
          m_res->addRes (framesize.stepwise.max_width, framesize.stepwise.max_height, V4L2_FRMSIZE_TYPE_CONTINUOUS);
 
251
          m_res->addRes (framesize.stepwise.min_width, framesize.stepwise.min_height, V4L2_FRMSIZE_TYPE_CONTINUOUS);
 
252
          break;
 
253
 
 
254
        case V4L2_FRMSIZE_TYPE_STEPWISE:
 
255
          m_res->addRes (framesize.stepwise.max_width, framesize.stepwise.max_height, V4L2_FRMSIZE_TYPE_STEPWISE);
 
256
          m_res->addRes (framesize.stepwise.min_width, framesize.stepwise.min_height, V4L2_FRMSIZE_TYPE_STEPWISE);
 
257
          m_res->addRes (framesize.stepwise.step_width, framesize.stepwise.step_height, V4L2_FRMSIZE_TYPE_STEPWISE);
 
258
          break;
 
259
 
 
260
        default:
 
261
          break;
 
262
      }
 
263
    }
121
264
    fmtdesc.index++;
122
265
  }
123
266
 
 
267
//gets the current resolution
124
268
  memset (&format, 0, sizeof (format));
125
269
  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
126
270
 
129
273
    return (false);
130
274
  }
131
275
 
 
276
  if (m_res) {
 
277
    m_res->setsX(format.fmt.pix.width);
 
278
  }
132
279
///////////// does not work with my ricoh and the uvcvideo module .... just comment out if needed
133
 
  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
134
 
  format.fmt.pix.width = 352;
135
 
  format.fmt.pix.height = 288;
136
 
  format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
137
 
  format.fmt.pix.field = V4L2_FIELD_ANY;
138
 
  if(0 == ioctl(fd, VIDIOC_TRY_FMT, &format)) {
139
 
    std::cerr << "--- we should be able to setup the resolution :)" << std::endl;
140
 
    if(-1 == ioctl(fd, VIDIOC_S_FMT, &format)) {
141
 
      error("VIDIOC_G_FMT: %s", strerror(errno));
142
 
      return(false);
143
 
    }
144
 
  }
 
280
//   format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
281
//   format.fmt.pix.width = 352;
 
282
//   format.fmt.pix.height = 288;
 
283
//   format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
 
284
//   format.fmt.pix.field = V4L2_FIELD_ANY;
 
285
//   if(0 == ioctl(fd, VIDIOC_TRY_FMT, &format)) {
 
286
//     std::cerr << "--- we should be able to setup the resolution :)" << std::endl;
 
287
//     if(-1 == ioctl(fd, VIDIOC_S_FMT, &format)) {
 
288
//       error("VIDIOC_S_FMT: %s", strerror(errno));
 
289
//       return(false);
 
290
//     }
 
291
//   }
145
292
 
146
293
  // Need to find out (request?) specific data format (sec 1.10.1)
147
294
  memset(&format, 0, sizeof(format));
163
310
  memset (&reqbuf, 0, sizeof (reqbuf));
164
311
  reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
165
312
  reqbuf.memory = V4L2_MEMORY_MMAP;
166
 
  reqbuf.count = 32;
 
313
  reqbuf.count = 4;     //reduced to reduce the display delay (thanks snawrocki)
167
314
  if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {
168
315
    if (errno == EINVAL)
169
316
      error("video capturing by mmap-streaming is not supported");
233
380
  act("%s is supported by V4L2 layer", devfile);
234
381
  opened = true;
235
382
 
 
383
  type = V4L2LAYER;
236
384
 
237
385
  return true;
238
386
}
239
387
 
 
388
Res *V4L2CamLayer::getRes() {
 
389
  return (m_res);
 
390
}
 
391
 
240
392
bool V4L2CamLayer::_init() {
241
393
 
242
394
  // format.fmt.pix.width = geo.w;
279
431
  return frame;
280
432
}
281
433
 
 
434
void V4L2CamLayer::chgRes(int idx, Res *res) {
 
435
  if(!opened) return;
 
436
  this->stop();
 
437
  // first, turn off streaming
 
438
  if(-1 == ioctl(fd, VIDIOC_STREAMOFF, &buftype)) {
 
439
    error("VIDIOC_STREAMOFF: %s", errno);
 
440
  }
 
441
  /* Cleanup. */
 
442
  for (unsigned int i = 0; i < reqbuf.count; i++)
 
443
    munmap (buffers[i].start, buffers[i].length);
 
444
 
 
445
  if (-1 == ::close (fd)) {
 
446
    error ("can't close the v4l2 opened device : %s", strerror (errno));
 
447
    this->start();
 
448
    return;
 
449
  }
 
450
  if (-1 == (fd = ::open(m_devfile,O_RDWR|O_NONBLOCK))) {
 
451
    error("error in opening video capture device: %s", m_devfile);
 
452
    this->start();
 
453
    return;
 
454
  } else {
 
455
    ::close(fd);
 
456
    fd = ::open(m_devfile,O_RDWR);
 
457
  }
 
458
 
 
459
  
 
460
  // Switch to the first video input (example 1-2)
 
461
  int index=0;
 
462
  if(-1 == ioctl(fd, VIDIOC_G_INPUT, &index)) {         //gets the current video input
 
463
    error("VIDIOC_G_INPUT: %s", strerror(errno));
 
464
    this->start();
 
465
    return;
 
466
  }
 
467
  // change the resolution
 
468
  memset (&format, 0, sizeof (format));
 
469
  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
470
 
 
471
  if (-1 == ioctl (fd, VIDIOC_G_FMT, &format)) {
 
472
    perror ("VIDIOC_G_FMT");
 
473
    this->start();
 
474
    return;
 
475
  }
 
476
//   memset (&format, 0, sizeof (format));
 
477
  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
478
  format.fmt.pix.width = res->getX(idx);
 
479
  format.fmt.pix.height = res->getY(idx);
 
480
  format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
 
481
  format.fmt.pix.field = V4L2_FIELD_ANY;
 
482
  if(0 == ioctl(fd, VIDIOC_TRY_FMT, &format)) {
 
483
    if(-1 == ioctl(fd, VIDIOC_S_FMT, &format)) {
 
484
      error("VIDIOC_S_FMT: %s", strerror(errno));
 
485
      this->start();
 
486
      return;
 
487
    }
 
488
  }
 
489
  memset (&format, 0, sizeof (format));
 
490
  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
491
 
 
492
  if (-1 == ioctl (fd, VIDIOC_G_FMT, &format)) {
 
493
    perror ("VIDIOC_G_FMT");
 
494
    this->start();
 
495
    return;
 
496
  }
 
497
  if ((format.fmt.pix.width != res->getX(idx)) || (format.fmt.pix.height != res->getY(idx))) {
 
498
    error ("couldn't change the resolution, still : %dx%d", format.fmt.pix.width, format.fmt.pix.height);
 
499
    this->start();
 
500
    return;
 
501
  }
 
502
  geo.init(format.fmt.pix.width, format.fmt.pix.height, 32);
 
503
  free (frame);
 
504
  frame = malloc(geo.bytesize);
 
505
 
 
506
  //////// init buffers
 
507
  memset (&reqbuf, 0, sizeof (reqbuf));
 
508
  reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
509
  reqbuf.memory = V4L2_MEMORY_MMAP;
 
510
  reqbuf.count = 4;     //reduced to reduce the display delay (thanks snawrocki)
 
511
  if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {
 
512
    if (errno == EINVAL)
 
513
      error("video capturing by mmap-streaming is not supported");
 
514
    else
 
515
      error ("VIDIOC_REQBUFS: %s", strerror(errno));
 
516
    this->start();
 
517
    return;
 
518
  }
 
519
  act("this cam supports %i buffers", reqbuf.count);
 
520
  free (buffers);
 
521
  buffers = (bufs*)calloc (reqbuf.count, sizeof (*buffers));
 
522
 
 
523
  if(format.fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) { // YUYV
 
524
    warning("pixel format not recognized, trying anyway as YUYV");
 
525
    warning("the system might become instable...");
 
526
  }
 
527
  
 
528
  for (unsigned int i = 0; i < reqbuf.count; i++) {
 
529
    
 
530
    memset (&buffer, 0, sizeof (buffer));
 
531
    buffer.type = reqbuf.type;
 
532
    buffer.memory = V4L2_MEMORY_MMAP;
 
533
    buffer.index = i;
 
534
    
 
535
    if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {
 
536
      error ("VIDIOC_QUERYBUF: %s", strerror(errno));
 
537
      this->start();
 
538
      return;
 
539
    }
 
540
    buffers[i].length = buffer.length; /* remember for munmap() */
 
541
    
 
542
    buffers[i].start = mmap (NULL, buffer.length,
 
543
                             PROT_READ | PROT_WRITE, /* recommended */
 
544
                             MAP_SHARED,             /* recommended */
 
545
                             fd, buffer.m.offset);
 
546
    
 
547
    if (MAP_FAILED == buffers[i].start) {
 
548
      /* If you do not exit here you should unmap() and free()
 
549
       *                    the buffers mapped so far. */
 
550
      error ("mmap: %s", strerror(errno));
 
551
      this->start();
 
552
      return;
 
553
    }
 
554
  }
 
555
 
 
556
  // OK, the memory is mapped, so let's queue up the buffers, turn on
 
557
  // streaming, and do the business
 
558
 
 
559
  // queue up all the buffers for the first time
 
560
  for (unsigned int i = 0; i < reqbuf.count; i++) {
 
561
    
 
562
    memset (&buffer, 0, sizeof (buffer));
 
563
    buffer.type = reqbuf.type;
 
564
    buffer.memory = V4L2_MEMORY_MMAP;
 
565
    buffer.index = i;
 
566
    buffer.length = buffers[i].length;
 
567
    
 
568
    if (-1 == ioctl (fd, VIDIOC_QBUF, &buffer)) {
 
569
      error ("first VIDIOC_QBUF: %s", strerror(errno));
 
570
      this->start();
 
571
      return;
 
572
    }
 
573
  }
 
574
 
 
575
  // turn on streaming
 
576
  if(-1 == ioctl(fd, VIDIOC_STREAMON, &buftype)) {
 
577
    error("VIDIOC_STREAMON: %s", strerror(errno));
 
578
    this->start();
 
579
    return;
 
580
  } 
 
581
  ////////
 
582
  this->start();
 
583
}
 
584
 
282
585
void V4L2CamLayer::close() {
283
586
  if(!opened) return;
284
587
  // If we've finished, turn off streaming