21 #if defined(HAVE_VIDEO4LINUX) && !defined(CPPPARSER)    25 #include <sys/ioctl.h>    38 #define clamp(x) std::min(std::max(x, 0.0), 255.0)    40 INLINE 
static void yuv_to_bgr(
unsigned char *dest, 
const unsigned char *src) {
    41   double y1 = (255 / 219.0) * (src[0] - 16);
    42   double pb = (255 / 224.0) * (src[1] - 128);
    43   double pr = (255 / 224.0) * (src[2] - 128);
    44   dest[2] = clamp(1.0 * y1 + 0     * pb + 1.402 * pr);
    45   dest[1] = clamp(1.0 * y1 - 0.344 * pb - 0.714 * pr);
    46   dest[0] = clamp(1.0 * y1 + 1.772 * pb + 0     * pr);
    49 INLINE 
static void yuyv_to_bgrbgr(
unsigned char *dest, 
const unsigned char *src) {
    50   unsigned char yuv[] = {src[0], src[1], src[3]};
    51   yuv_to_bgr(dest, yuv);
    53   yuv_to_bgr(dest + 3, yuv);
    56 INLINE 
static void yuyv_to_bgrabgra(
unsigned char *dest, 
const unsigned char *src) {
    57   unsigned char yuv[] = {src[0], src[1], src[3]};
    58   yuv_to_bgr(dest, yuv);
    60   yuv_to_bgr(dest + 4, yuv);
    65 INLINE 
static void rgb_to_bgr(
unsigned char *dest, 
const unsigned char *src) {
    71 INLINE 
static void rgb_to_bgra(
unsigned char *dest, 
const unsigned char *src) {
    78 #if defined(HAVE_JPEG) && !defined(CPPPARSER)    81   struct jpeg_error_mgr pub;
    82   jmp_buf setjmp_buffer;
    85 typedef struct my_error_mgr *my_error_ptr;
    87 static void my_error_exit (j_common_ptr cinfo) {
    89   char buffer[JMSG_LENGTH_MAX];
    90   (*cinfo->err->format_message) (cinfo, buffer);
    91   vision_cat.error() << buffer << 
"\n";
    93   my_error_ptr myerr = (my_error_ptr) cinfo->err;
    95   longjmp(myerr->setjmp_buffer, 1);
    98 static void my_output_message (j_common_ptr cinfo){
    99   char buffer[JMSG_LENGTH_MAX];
   100   (*cinfo->err->format_message) (cinfo, buffer);
   101   vision_cat.warning() << buffer << 
"\n";
   104 static void my_init_source(j_decompress_ptr cinfo) {
   107 static boolean my_fill_input_buffer(j_decompress_ptr cinfo) {
   108   struct jpeg_source_mgr *src = cinfo->src;
   109   static JOCTET FakeEOI[] = {0xFF, JPEG_EOI};
   111   WARNMS(cinfo, JWRN_JPEG_EOF);
   113   src->next_input_byte = FakeEOI;
   114   src->bytes_in_buffer = 2;
   119 static void my_skip_input_data(j_decompress_ptr cinfo, 
long num_bytes) {
   120   struct jpeg_source_mgr *src = cinfo->src;
   122   if (num_bytes >= (
long) src->bytes_in_buffer) {
   123     my_fill_input_buffer(cinfo);
   127   src->bytes_in_buffer -= num_bytes;
   128   src->next_input_byte += num_bytes;
   131 static void my_term_source(j_decompress_ptr cinfo) {
   135 static JHUFF_TBL dc_luminance_tbl = {
   136   {0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0},
   137   {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
   141 static JHUFF_TBL dc_chrominance_tbl = {
   142   {0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
   143   {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
   147 static JHUFF_TBL ac_luminance_tbl = {
   148   {0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d},
   150     0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
   151     0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71,
   152     0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1,
   153     0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,
   154     0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25,
   155     0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
   156     0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
   157     0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
   158     0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
   159     0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
   160     0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93,
   161     0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3,
   162     0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3,
   163     0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
   164     0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3,
   165     0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
   166     0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
   167     0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
   172 static JHUFF_TBL ac_chrominance_tbl = {
   173   {0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77},
   175     0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31,
   176     0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
   177     0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1,
   178     0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1,
   179     0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18,
   180     0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36,
   181     0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47,
   182     0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
   183     0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
   184     0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
   185     0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
   186     0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
   187     0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
   188     0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
   189     0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca,
   190     0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
   191     0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
   192     0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
   202 WebcamVideoCursorV4L::
   204   _size_x = src->_size_x;
   205   _size_y = src->_size_y;
   209   _can_seek_fast = 
false;
   213   memset(&_format, 0, 
sizeof(
struct v4l2_format));
   223   _fd = open(src->_device.c_str(), mode);
   225     vision_cat.error() << 
"Failed to open " << src->_device.c_str() << 
"\n";
   231   _format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   232   _format.fmt.pix.pixelformat = src->_pformat;
   234   switch (_format.fmt.pix.pixelformat) {
   236   case V4L2_PIX_FMT_MJPEG:
   241   case V4L2_PIX_FMT_YUYV:
   245   case V4L2_PIX_FMT_BGR24:
   249   case V4L2_PIX_FMT_BGR32:
   253   case V4L2_PIX_FMT_RGB24:
   257   case V4L2_PIX_FMT_RGB32:
   261   case V4L2_PIX_FMT_GREY:
   266     vision_cat.error() << 
"Unsupported pixel format " << src->get_pixel_format() << 
"!\n";
   274   _format.fmt.pix.width = _size_x;
   275   _format.fmt.pix.height = _size_y;
   276   _format.fmt.pix.field = V4L2_FIELD_NONE;
   279   if (-1 == ioctl(_fd, VIDIOC_S_FMT, &_format)) {
   280     vision_cat.error() << 
"Driver rejected format!\n";
   287   _size_x = _format.fmt.pix.width;
   288   _size_y = _format.fmt.pix.height;
   290   struct v4l2_streamparm streamparm;
   291   memset(&streamparm, 0, 
sizeof streamparm);
   292   streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   293   streamparm.parm.capture.timeperframe.numerator = 1;
   294   streamparm.parm.capture.timeperframe.denominator = src->_fps;
   295   if (ioctl(_fd, VIDIOC_S_PARM, &streamparm) < 0) {
   296     vision_cat.error() << 
"Driver rejected framerate!\n";
   299   struct v4l2_requestbuffers req;
   300   memset(&req, 0, 
sizeof req);
   302   req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   303   req.memory = V4L2_MEMORY_MMAP;
   305   if (-1 == ioctl (_fd, VIDIOC_REQBUFS, &req)) {
   306     vision_cat.error() << 
"Failed to request buffers from webcam!\n";
   310     vision_cat.error() << 
"Insufficient buffer memory!\n";
   313   _bufcount = req.count;
   314   _buffers = (
void **) calloc (req.count, sizeof (
void*));
   315   _buflens = (
size_t*) calloc (req.count, sizeof (
size_t));
   317   if (!_buffers || !_buflens) {
   318     vision_cat.error() << 
"Not enough memory!\n";
   322   struct v4l2_buffer buf;
   323   for (
unsigned int i = 0; i < (
unsigned int)_bufcount; ++i) {
   324     memset(&buf, 0, 
sizeof buf);
   325     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   326     buf.memory = V4L2_MEMORY_MMAP;
   329     if (-1 == ioctl(_fd, VIDIOC_QUERYBUF, &buf)) {
   330       vision_cat.error() << 
"Failed to query buffer!\n";
   333     _buflens[i] = buf.length;
   334     _buffers[i] = mmap (
nullptr, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, buf.m.offset);
   336     if (_buffers[i] == MAP_FAILED) {
   337       vision_cat.error() << 
"Failed to map buffer!\n";
   340     if (-1 == ioctl(_fd, VIDIOC_QBUF, &buf)) {
   341       vision_cat.error() << 
"Failed to exchange buffer with driver!\n";
   345   enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   346   if (-1 == ioctl(_fd, VIDIOC_STREAMON, &type)) {
   347     vision_cat.error() << 
"Failed to stream from buffer!\n";
   352   if (_format.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
   353     jpeg_create_decompress(&_cinfo);
   355     _cinfo.src = (
struct jpeg_source_mgr *)
   356       (*_cinfo.mem->alloc_small) ((j_common_ptr) &_cinfo, JPOOL_PERMANENT,
   357                                           sizeof(
struct jpeg_source_mgr));
   359     _cinfo.src->init_source = my_init_source;
   360     _cinfo.src->fill_input_buffer = my_fill_input_buffer;
   361     _cinfo.src->skip_input_data = my_skip_input_data;
   362     _cinfo.src->resync_to_restart = jpeg_resync_to_restart;
   363     _cinfo.src->term_source = my_term_source;
   372 WebcamVideoCursorV4L::
   373 ~WebcamVideoCursorV4L() {
   375   if (_format.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
   376     jpeg_destroy_decompress(&_cinfo);
   380     enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   381     ioctl(_fd, VIDIOC_STREAMOFF, &type);
   385     for (
unsigned int i = 0; i < (
unsigned int)_bufcount; ++i) {
   386       munmap(_buffers[i], _buflens[i]);
   404   PT(
Buffer) buffer = get_standard_buffer();
   405   unsigned char *block = buffer->_block;
   406   struct v4l2_buffer vbuf;
   407   memset(&vbuf, 0, 
sizeof vbuf);
   408   vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   409   vbuf.memory = V4L2_MEMORY_MMAP;
   410   if (-1 == ioctl(_fd, VIDIOC_DQBUF, &vbuf) && errno != EIO) {
   411     if (errno == EAGAIN) {
   415     vision_cat.error() << 
"Failed to dequeue buffer!\n";
   418   nassertr(vbuf.index < _bufcount, 
nullptr);
   419   size_t bufsize = _buflens[vbuf.index];
   420   size_t old_bpl = _format.fmt.pix.bytesperline;
   421   size_t new_bpl = _size_x * _num_components;
   422   unsigned char *buf = (
unsigned char *) _buffers[vbuf.index];
   424   switch (_format.fmt.pix.pixelformat) {
   425   case V4L2_PIX_FMT_MJPEG: {
   427     struct my_error_mgr jerr;
   428     _cinfo.err = jpeg_std_error(&jerr.pub);
   429     jerr.pub.error_exit = my_error_exit;
   430     jerr.pub.output_message = my_output_message;
   432     unsigned char *newbuf = (
unsigned char*) malloc(new_bpl * _size_y);
   435     if (setjmp(jerr.setjmp_buffer)) {
   436       jpeg_abort_decompress(&_cinfo);
   439       _cinfo.src->bytes_in_buffer = bufsize;
   440       _cinfo.src->next_input_byte = buf;
   442       if (jpeg_read_header(&_cinfo, TRUE) == JPEG_HEADER_OK) {
   443         if (_cinfo.dc_huff_tbl_ptrs[0] == 
nullptr) {
   445           _cinfo.dc_huff_tbl_ptrs[0] = &dc_luminance_tbl;
   446           _cinfo.dc_huff_tbl_ptrs[1] = &dc_chrominance_tbl;
   447           _cinfo.ac_huff_tbl_ptrs[0] = &ac_luminance_tbl;
   448           _cinfo.ac_huff_tbl_ptrs[1] = &ac_chrominance_tbl;
   451         _cinfo.scale_num = 1;
   452         _cinfo.scale_denom = 1;
   453         _cinfo.out_color_space = JCS_RGB;
   454         _cinfo.dct_method = JDCT_IFAST;
   456         if (jpeg_start_decompress(&_cinfo) && _cinfo.output_components == 3
   457           && _size_x == _cinfo.output_width && _size_y == _cinfo.output_height) {
   459           JSAMPLE *buffer_end = newbuf + new_bpl * _cinfo.output_height;
   460           JSAMPLE *rowptr = newbuf;
   461           while (_cinfo.output_scanline < _cinfo.output_height) {
   462             nassertd(rowptr + new_bpl <= buffer_end) 
break;
   463             jpeg_read_scanlines(&_cinfo, &rowptr, _cinfo.output_height);
   467           if (_cinfo.output_scanline < _cinfo.output_height) {
   468             jpeg_abort_decompress(&_cinfo);
   470             jpeg_finish_decompress(&_cinfo);
   477     for (
int row = 0; row < _size_y; ++row) {
   478       memcpy(block + (_size_y - row - 1) * new_bpl, newbuf + row * new_bpl, new_bpl);
   484     for (
size_t i = 0; i < new_bpl * _size_y; i += 3) {
   486       block[i] = block[i + 2];
   490     nassert_raise(
"JPEG support not compiled-in");
   495   case V4L2_PIX_FMT_YUYV:
   496     for (
size_t row = 0; row < _size_y; ++row) {
   498       for (
size_t i = 0; i < old_bpl; i += 4) {
   499         yuyv_to_bgrbgr(block + (_size_y - row - 1) * new_bpl + c, buf + row * old_bpl + i);
   505   case V4L2_PIX_FMT_BGR24:
   506   case V4L2_PIX_FMT_BGR32:
   507   case V4L2_PIX_FMT_GREY:
   509     nassertr(old_bpl == new_bpl, 
nullptr);
   511     for (
size_t row = 0; row < _size_y; ++row) {
   512       memcpy(block + (_size_y - row - 1) * new_bpl, buf + row * old_bpl, new_bpl);
   516   case V4L2_PIX_FMT_RGB24:
   518     nassertr(old_bpl == new_bpl, 
nullptr);
   520     for (
size_t row = 0; row < _size_y; ++row) {
   521       for (
size_t i = 0; i < old_bpl; i += 3) {
   522         rgb_to_bgr(block + (_size_y - row - 1) * old_bpl + i, buf + row * old_bpl + i);
   527   case V4L2_PIX_FMT_RGB32:
   529     nassertr(old_bpl == new_bpl, 
nullptr);
   531     for (
size_t row = 0; row < _size_y; ++row) {
   532       for (
size_t i = 0; i < old_bpl; i += 4) {
   533         rgb_to_bgra(block + (_size_y - row - 1) * old_bpl + i, buf + row * old_bpl + i + 1);
   539   if (-1 == ioctl(_fd, VIDIOC_QBUF, &vbuf)) {
   540     vision_cat.error() << 
"Failed to exchange buffer with driver!\n";
 PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
 
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
 
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
 
A MovieVideo is actually any source that provides a sequence of video frames.
 
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
 
TypeHandle is the identifier used to differentiate C++ class types.