From de95ed855dccc51ca0209d87f278ea50e2e5fe42 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 24 Sep 2014 15:33:40 +0000 Subject: [PATCH] Support enumeration of different pixel formats in WebcamVideo, support for RGB pixel formats in Video4Linux --- panda/src/vision/webcamVideo.I | 21 ++- panda/src/vision/webcamVideo.h | 6 +- panda/src/vision/webcamVideoCursorV4L.cxx | 216 ++++++++++++++-------- panda/src/vision/webcamVideoCursorV4L.h | 12 +- panda/src/vision/webcamVideoV4L.cxx | 142 ++++++++++---- panda/src/vision/webcamVideoV4L.h | 5 +- 6 files changed, 273 insertions(+), 129 deletions(-) diff --git a/panda/src/vision/webcamVideo.I b/panda/src/vision/webcamVideo.I index 356e5c568b..23242cff83 100644 --- a/panda/src/vision/webcamVideo.I +++ b/panda/src/vision/webcamVideo.I @@ -40,11 +40,22 @@ get_size_y() const { // is a maximum theoretical: the actual performance // will depend on the speed of the hardware. //////////////////////////////////////////////////////////////////// -INLINE int WebcamVideo:: +INLINE double WebcamVideo:: get_fps() const { return _fps; } +//////////////////////////////////////////////////////////////////// +// Function: WebcamVideo::get_pixel_format +// Access: Published +// Description: Returns the camera's pixel format, as a FourCC code, +// if known. +//////////////////////////////////////////////////////////////////// +INLINE const string &WebcamVideo:: +get_pixel_format() const { + return _pixel_format; +} + //////////////////////////////////////////////////////////////////// // Function: WebcamVideo::output // Access: Public @@ -53,7 +64,13 @@ get_fps() const { //////////////////////////////////////////////////////////////////// INLINE void WebcamVideo:: output(ostream &out) const { - out << get_name() << ": " << get_size_x() << "x" << get_size_y() << " @ " << get_fps() << "Hz"; + out << get_name() << ": " << get_size_x() << "x" << get_size_y(); + + if (!_pixel_format.empty()) { + out << " " << _pixel_format; + } + + out << " @ " << get_fps() << "Hz"; } INLINE ostream &operator << (ostream &out, const WebcamVideo &n) { diff --git a/panda/src/vision/webcamVideo.h b/panda/src/vision/webcamVideo.h index 94a0b431c7..bcaafc92b4 100644 --- a/panda/src/vision/webcamVideo.h +++ b/panda/src/vision/webcamVideo.h @@ -33,7 +33,8 @@ PUBLISHED: INLINE int get_size_x() const; INLINE int get_size_y() const; - INLINE int get_fps() const; + INLINE double get_fps() const; + INLINE const string &get_pixel_format() const; virtual PT(MovieVideoCursor) open() = 0; @@ -45,7 +46,8 @@ public: protected: int _size_x; int _size_y; - int _fps; + double _fps; + string _pixel_format; static pvector _all_webcams; diff --git a/panda/src/vision/webcamVideoCursorV4L.cxx b/panda/src/vision/webcamVideoCursorV4L.cxx index 9513b9bfe1..e787ff658f 100644 --- a/panda/src/vision/webcamVideoCursorV4L.cxx +++ b/panda/src/vision/webcamVideoCursorV4L.cxx @@ -19,7 +19,6 @@ #include #include #include -#include #ifdef HAVE_JPEG extern "C" { @@ -34,7 +33,7 @@ TypeHandle WebcamVideoCursorV4L::_type_handle; #define clamp(x) min(max(x, 0.0), 255.0) -INLINE static void yuv_to_rgb(unsigned char *dest, const unsigned char *src) { +INLINE static void yuv_to_bgr(unsigned char *dest, const unsigned char *src) { double y1 = (255 / 219.0) * (src[0] - 16); double pb = (255 / 224.0) * (src[1] - 128); double pr = (255 / 224.0) * (src[2] - 128); @@ -43,20 +42,33 @@ INLINE static void yuv_to_rgb(unsigned char *dest, const unsigned char *src) { dest[0] = clamp(1.0 * y1 + 1.772 * pb + 0 * pr); } -INLINE static void yuyv_to_rgbrgb(unsigned char *dest, const unsigned char *src) { +INLINE static void yuyv_to_bgrbgr(unsigned char *dest, const unsigned char *src) { unsigned char yuv[] = {src[0], src[1], src[3]}; - yuv_to_rgb(dest, yuv); + yuv_to_bgr(dest, yuv); yuv[0] = src[2]; - yuv_to_rgb(dest + 3, yuv); + yuv_to_bgr(dest + 3, yuv); } -INLINE static void yuyv_to_rgbargba(unsigned char *dest, const unsigned char *src) { +INLINE static void yuyv_to_bgrabgra(unsigned char *dest, const unsigned char *src) { unsigned char yuv[] = {src[0], src[1], src[3]}; - yuv_to_rgb(dest, yuv); + yuv_to_bgr(dest, yuv); yuv[0] = src[2]; - yuv_to_rgb(dest + 4, yuv); - dest[3] = (unsigned char) -1; - dest[7] = (unsigned char) -1; + yuv_to_bgr(dest + 4, yuv); + dest[3] = 0xff; + dest[7] = 0xff; +} + +INLINE static void rgb_to_bgr(unsigned char *dest, const unsigned char *src) { + dest[0] = src[2]; + dest[1] = src[1]; + dest[2] = src[0]; +} + +INLINE static void rgb_to_bgra(unsigned char *dest, const unsigned char *src) { + dest[0] = src[2]; + dest[1] = src[1]; + dest[2] = src[0]; + dest[3] = 0xff; } #if defined(HAVE_JPEG) && !defined(CPPPARSER) @@ -196,11 +208,8 @@ WebcamVideoCursorV4L(WebcamVideoV4L *src) : MovieVideoCursor(src) { _aborted = false; _streaming = true; _ready = false; - _format = (struct v4l2_format *) malloc(sizeof(struct v4l2_format)); - memset(_format, 0, sizeof(struct v4l2_format)); -#ifdef HAVE_JPEG - _cinfo = NULL; -#endif + memset(&_format, 0, sizeof(struct v4l2_format)); + _buffers = NULL; _buflens = NULL; _fd = open(src->_device.c_str(), O_RDWR); @@ -211,22 +220,38 @@ WebcamVideoCursorV4L(WebcamVideoV4L *src) : MovieVideoCursor(src) { // Find the best format in our _pformats vector. // MJPEG is preferred over YUYV, as it's much smaller. - _format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - pvector::iterator it; - for (it = src->_pformats.begin(); it != src->_pformats.end(); ++it) { + _format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + _format.fmt.pix.pixelformat = src->_pformat; + + switch (_format.fmt.pix.pixelformat) { #ifdef HAVE_JPEG - if (*it == V4L2_PIX_FMT_MJPEG) { - _format->fmt.pix.pixelformat = *it; - break; - } else + case V4L2_PIX_FMT_MJPEG: + _num_components = 3; + break; #endif - if (*it == V4L2_PIX_FMT_YUYV) { - _format->fmt.pix.pixelformat = *it; - break; - } - } - if (it == src->_pformats.end()) { - vision_cat.error() << "Failed to find a suitable pixel format!\n"; + + case V4L2_PIX_FMT_YUYV: + _num_components = 3; + break; + + case V4L2_PIX_FMT_BGR24: + _num_components = 3; + break; + + case V4L2_PIX_FMT_BGR32: + _num_components = 4; + break; + + case V4L2_PIX_FMT_RGB24: + _num_components = 3; + break; + + case V4L2_PIX_FMT_RGB32: + _num_components = 4; + break; + + default: + vision_cat.error() << "Unsupported pixel format " << src->get_pixel_format() << "!\n"; _ready = false; close(_fd); _fd = -1; @@ -234,12 +259,12 @@ WebcamVideoCursorV4L(WebcamVideoV4L *src) : MovieVideoCursor(src) { } // Request a format of this size, and no interlacing - _format->fmt.pix.width = _size_x; - _format->fmt.pix.height = _size_y; - _format->fmt.pix.field = V4L2_FIELD_NONE; + _format.fmt.pix.width = _size_x; + _format.fmt.pix.height = _size_y; + _format.fmt.pix.field = V4L2_FIELD_NONE; // Now politely ask the driver to switch to this format - if (-1 == ioctl(_fd, VIDIOC_S_FMT, _format)) { + if (-1 == ioctl(_fd, VIDIOC_S_FMT, &_format)) { vision_cat.error() << "Driver rejected format!\n"; _ready = false; close(_fd); @@ -247,8 +272,8 @@ WebcamVideoCursorV4L(WebcamVideoV4L *src) : MovieVideoCursor(src) { return; } - _size_x = _format->fmt.pix.width; - _size_y = _format->fmt.pix.height; + _size_x = _format.fmt.pix.width; + _size_y = _format.fmt.pix.height; struct v4l2_streamparm streamparm; memset(&streamparm, 0, sizeof streamparm); @@ -274,7 +299,7 @@ WebcamVideoCursorV4L(WebcamVideoV4L *src) : MovieVideoCursor(src) { } _bufcount = req.count; - _buffers = (void* *) calloc (req.count, sizeof (void*)); + _buffers = (void **) calloc (req.count, sizeof (void*)); _buflens = (size_t*) calloc (req.count, sizeof (size_t)); if (!_buffers || !_buflens) { @@ -312,19 +337,18 @@ WebcamVideoCursorV4L(WebcamVideoV4L *src) : MovieVideoCursor(src) { #ifdef HAVE_JPEG // Initialize the JPEG library, if necessary - if (_format->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) { - _cinfo = (struct jpeg_decompress_struct *) malloc(sizeof(struct jpeg_decompress_struct)); - jpeg_create_decompress(_cinfo); + if (_format.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) { + jpeg_create_decompress(&_cinfo); - _cinfo->src = (struct jpeg_source_mgr *) - (*_cinfo->mem->alloc_small) ((j_common_ptr) _cinfo, JPOOL_PERMANENT, + _cinfo.src = (struct jpeg_source_mgr *) + (*_cinfo.mem->alloc_small) ((j_common_ptr) &_cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr)); // Set up function pointers - _cinfo->src->init_source = my_init_source; - _cinfo->src->fill_input_buffer = my_fill_input_buffer; - _cinfo->src->skip_input_data = my_skip_input_data; - _cinfo->src->resync_to_restart = jpeg_resync_to_restart; - _cinfo->src->term_source = my_term_source; + _cinfo.src->init_source = my_init_source; + _cinfo.src->fill_input_buffer = my_fill_input_buffer; + _cinfo.src->skip_input_data = my_skip_input_data; + _cinfo.src->resync_to_restart = jpeg_resync_to_restart; + _cinfo.src->term_source = my_term_source; } #endif _ready = true; @@ -338,14 +362,10 @@ WebcamVideoCursorV4L(WebcamVideoV4L *src) : MovieVideoCursor(src) { WebcamVideoCursorV4L:: ~WebcamVideoCursorV4L() { #ifdef HAVE_JPEG - if (_cinfo != NULL) { - jpeg_destroy_decompress(_cinfo); - free(_cinfo); + if (_format.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) { + jpeg_destroy_decompress(&_cinfo); } #endif - if (_format != NULL) { - free(_format); - } if (-1 != _fd) { enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(_fd, VIDIOC_STREAMOFF, &type); @@ -385,14 +405,15 @@ fetch_buffer() { } nassertr(vbuf.index < _bufcount, NULL); size_t bufsize = _buflens[vbuf.index]; - size_t old_bpl = _format->fmt.pix.bytesperline; - size_t new_bpl = _size_x * 3; + size_t old_bpl = _format.fmt.pix.bytesperline; + size_t new_bpl = _size_x * _num_components; unsigned char *buf = (unsigned char *) _buffers[vbuf.index]; - if (_format->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) { + switch (_format.fmt.pix.pixelformat) { + case V4L2_PIX_FMT_MJPEG: { #ifdef HAVE_JPEG struct my_error_mgr jerr; - _cinfo->err = jpeg_std_error(&jerr.pub); + _cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; jerr.pub.output_message = my_output_message; @@ -400,41 +421,41 @@ fetch_buffer() { // Establish the setjmp return context for my_error_exit to use if (setjmp(jerr.setjmp_buffer)) { - jpeg_abort_decompress(_cinfo); + jpeg_abort_decompress(&_cinfo); } else { // Set up data pointer - _cinfo->src->bytes_in_buffer = bufsize; - _cinfo->src->next_input_byte = buf; + _cinfo.src->bytes_in_buffer = bufsize; + _cinfo.src->next_input_byte = buf; - if (jpeg_read_header(_cinfo, TRUE) == JPEG_HEADER_OK) { - if (_cinfo->dc_huff_tbl_ptrs[0] == NULL) { + if (jpeg_read_header(&_cinfo, TRUE) == JPEG_HEADER_OK) { + if (_cinfo.dc_huff_tbl_ptrs[0] == NULL) { // Many MJPEG streams do not include huffman tables. Remedy this. - _cinfo->dc_huff_tbl_ptrs[0] = &dc_luminance_tbl; - _cinfo->dc_huff_tbl_ptrs[1] = &dc_chrominance_tbl; - _cinfo->ac_huff_tbl_ptrs[0] = &ac_luminance_tbl; - _cinfo->ac_huff_tbl_ptrs[1] = &ac_chrominance_tbl; + _cinfo.dc_huff_tbl_ptrs[0] = &dc_luminance_tbl; + _cinfo.dc_huff_tbl_ptrs[1] = &dc_chrominance_tbl; + _cinfo.ac_huff_tbl_ptrs[0] = &ac_luminance_tbl; + _cinfo.ac_huff_tbl_ptrs[1] = &ac_chrominance_tbl; } - _cinfo->scale_num = 1; - _cinfo->scale_denom = 1; - _cinfo->out_color_space = JCS_RGB; - _cinfo->dct_method = JDCT_IFAST; + _cinfo.scale_num = 1; + _cinfo.scale_denom = 1; + _cinfo.out_color_space = JCS_RGB; + _cinfo.dct_method = JDCT_IFAST; - if (jpeg_start_decompress(_cinfo) && _cinfo->output_components == 3 - && _size_x == _cinfo->output_width && _size_y == _cinfo->output_height) { + if (jpeg_start_decompress(&_cinfo) && _cinfo.output_components == 3 + && _size_x == _cinfo.output_width && _size_y == _cinfo.output_height) { - JSAMPLE *buffer_end = newbuf + new_bpl * _cinfo->output_height; + JSAMPLE *buffer_end = newbuf + new_bpl * _cinfo.output_height; JSAMPLE *rowptr = newbuf; - while (_cinfo->output_scanline < _cinfo->output_height) { + while (_cinfo.output_scanline < _cinfo.output_height) { nassertd(rowptr + new_bpl <= buffer_end) break; - jpeg_read_scanlines(_cinfo, &rowptr, _cinfo->output_height); + jpeg_read_scanlines(&_cinfo, &rowptr, _cinfo.output_height); rowptr += new_bpl; } - if (_cinfo->output_scanline < _cinfo->output_height) { - jpeg_abort_decompress(_cinfo); + if (_cinfo.output_scanline < _cinfo.output_height) { + jpeg_abort_decompress(&_cinfo); } else { - jpeg_finish_decompress(_cinfo); + jpeg_finish_decompress(&_cinfo); } } } @@ -454,16 +475,51 @@ fetch_buffer() { block[i + 2] = ex; } #else - nassertr(false, NULL); // Not compiled with JPEG support + nassertr(false /* Not compiled with JPEG support*/, NULL); #endif - } else { + break; + } + case V4L2_PIX_FMT_YUYV: for (size_t row = 0; row < _size_y; ++row) { size_t c = 0; for (size_t i = 0; i < old_bpl; i += 4) { - yuyv_to_rgbrgb(block + (_size_y - row - 1) * new_bpl + c, buf + row * old_bpl + i); + yuyv_to_bgrbgr(block + (_size_y - row - 1) * new_bpl + c, buf + row * old_bpl + i); c += 6; } } + break; + + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_BGR32: + // Simplest case: copying every row verbatim. + nassertr(old_bpl == new_bpl, NULL); + + for (size_t row = 0; row < _size_y; ++row) { + memcpy(block + (_size_y - row - 1) * new_bpl, buf + row * old_bpl, new_bpl); + } + break; + + case V4L2_PIX_FMT_RGB24: + // Swap components. + nassertr(old_bpl == new_bpl, NULL); + + for (size_t row = 0; row < _size_y; ++row) { + for (size_t i = 0; i < old_bpl; i += 3) { + rgb_to_bgr(block + (_size_y - row - 1) * old_bpl + i, buf + row * old_bpl + i); + } + } + break; + + case V4L2_PIX_FMT_RGB32: + // Swap components. + nassertr(old_bpl == new_bpl, NULL); + + for (size_t row = 0; row < _size_y; ++row) { + for (size_t i = 0; i < old_bpl; i += 4) { + rgb_to_bgra(block + (_size_y - row - 1) * old_bpl + i, buf + row * old_bpl + i + 1); + } + } + break; } if (-1 == ioctl(_fd, VIDIOC_QBUF, &vbuf)) { diff --git a/panda/src/vision/webcamVideoCursorV4L.h b/panda/src/vision/webcamVideoCursorV4L.h index 88edeaab6b..14ffa257f2 100644 --- a/panda/src/vision/webcamVideoCursorV4L.h +++ b/panda/src/vision/webcamVideoCursorV4L.h @@ -22,10 +22,12 @@ #include "webcamVideo.h" #include "movieVideoCursor.h" -struct v4l2_format; +#include -#if defined(HAVE_JPEG) -struct jpeg_decompress_struct; +#ifdef HAVE_JPEG +extern "C" { + #include +} #endif class WebcamVideoV4L; @@ -45,9 +47,9 @@ private: void **_buffers; size_t *_buflens; size_t _bufcount; - struct v4l2_format *_format; + struct v4l2_format _format; #ifdef HAVE_JPEG - struct jpeg_decompress_struct *_cinfo; + struct jpeg_decompress_struct _cinfo; #endif public: diff --git a/panda/src/vision/webcamVideoV4L.cxx b/panda/src/vision/webcamVideoV4L.cxx index 5b9b9992f5..71cee3d312 100644 --- a/panda/src/vision/webcamVideoV4L.cxx +++ b/panda/src/vision/webcamVideoV4L.cxx @@ -25,6 +25,56 @@ TypeHandle WebcamVideoV4L::_type_handle; +//////////////////////////////////////////////////////////////////// +// Function: add_options_for_size +// Access: Private, Static +// Description: +//////////////////////////////////////////////////////////////////// +void WebcamVideoV4L:: +add_options_for_size(int fd, const string &dev, const char *name, unsigned width, unsigned height, unsigned pixelformat) { + struct v4l2_frmivalenum frmivalenum; + for (int k = 0;; k++) { + memset(&frmivalenum, 0, sizeof frmivalenum); + frmivalenum.index = k; + frmivalenum.pixel_format = pixelformat; + frmivalenum.width = width; + frmivalenum.height = height; + if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmivalenum) == -1) { + break; + } + double fps = 0.0; + switch (frmivalenum.type) { + case V4L2_FRMIVAL_TYPE_DISCRETE: + fps = ((double) frmivalenum.discrete.denominator) / ((double) frmivalenum.discrete.numerator); + break; + + case V4L2_FRMIVAL_TYPE_CONTINUOUS: + case V4L2_FRMIVAL_TYPE_STEPWISE: + { + // Select the maximum framerate. + double max_fps = ((double) frmivalenum.stepwise.max.denominator) / ((double) frmivalenum.stepwise.max.numerator); + fps = max_fps; + } + break; + + default: + continue; + } + + // Create a new webcam video object + PT(WebcamVideoV4L) wc = new WebcamVideoV4L; + wc->set_name(name); + wc->_device = dev; + wc->_size_x = width; + wc->_size_y = height; + wc->_fps = fps; + wc->_pformat = pixelformat; + wc->_pixel_format = string((char*) &pixelformat, 4); + + WebcamVideoV4L::_all_webcams.push_back(DCAST(WebcamVideo, wc)); + } +} + //////////////////////////////////////////////////////////////////// // Function: find_all_webcams_v4l // Access: Public, Static @@ -52,6 +102,23 @@ void find_all_webcams_v4l() { if (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == -1) { break; } + + // Only accept supported formats. + switch (fmt.pixelformat) { +#ifdef HAVE_JPEG + case V4L2_PIX_FMT_MJPEG: +#endif + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_RGB32: + break; + + default: + continue; + } + struct v4l2_frmsizeenum frmsizeenum; for (int j = 0;; j++) { memset(&frmsizeenum, 0, sizeof frmsizeenum); @@ -60,51 +127,48 @@ void find_all_webcams_v4l() { if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsizeenum) == -1) { break; } - if (frmsizeenum.type != V4L2_FRMSIZE_TYPE_DISCRETE) { - continue; - } - struct v4l2_frmivalenum frmivalenum; - for (int k = 0;; k++) { - memset(&frmivalenum, 0, sizeof frmivalenum); - frmivalenum.index = k; - frmivalenum.pixel_format = fmt.pixelformat; - frmivalenum.width = frmsizeenum.discrete.width; - frmivalenum.height = frmsizeenum.discrete.height; - if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmivalenum) == -1) { - break; - } - if (frmivalenum.type != V4L2_FRMIVAL_TYPE_DISCRETE) { - continue; - } - // Create a new webcam video object - PT(WebcamVideoV4L) wc = new WebcamVideoV4L; - wc->set_name((const char*) cap2.card); - wc->_device = *it; - wc->_size_x = frmsizeenum.discrete.width; - wc->_size_y = frmsizeenum.discrete.height; - wc->_fps = ((double) frmivalenum.discrete.denominator) / ((double) frmivalenum.discrete.numerator); - wc->_pformats.push_back(fmt.pixelformat); + switch (frmsizeenum.type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + // Easy, add the options with this discrete size. + WebcamVideoV4L:: + add_options_for_size(fd, *it, (const char *)cap2.card, + frmsizeenum.discrete.width, + frmsizeenum.discrete.height, + fmt.pixelformat); + break; - // Iterate through the webcams to make sure we don't put any duplicates in there - pvector::iterator wvi; - for (wvi = WebcamVideoV4L::_all_webcams.begin(); wvi != WebcamVideoV4L::_all_webcams.end(); ++wvi) { - if ((*wvi)->is_of_type(WebcamVideoV4L::get_class_type())) { - PT(WebcamVideoV4L) wv_v4l = DCAST(WebcamVideoV4L, *wvi); - if (wv_v4l->_device == wc->_device && - wv_v4l->_size_x == wc->_size_x && - wv_v4l->_size_y == wc->_size_y && - wv_v4l->_fps == wc->_fps) { - wv_v4l->_pformats.push_back(fmt.pixelformat); - break; + case V4L2_FRMSIZE_TYPE_CONTINUOUS: + { + // Okay, er, we don't have a proper handling of this, + // so let's add all powers of two in this range. + + __u32 width = Texture::up_to_power_2(frmsizeenum.stepwise.min_width); + for (; width <= frmsizeenum.stepwise.max_width; width *= 2) { + __u32 height = Texture::up_to_power_2(frmsizeenum.stepwise.min_height); + for (; height <= frmsizeenum.stepwise.max_height; height *= 2) { + WebcamVideoV4L:: + add_options_for_size(fd, *it, (const char *)cap2.card, width, height, fmt.pixelformat); } } } - // Did the loop finish, meaning that a webcam of these - // properties does not exist? Add it. - if (wvi == WebcamVideoV4L::_all_webcams.end()) { - WebcamVideoV4L::_all_webcams.push_back(DCAST(WebcamVideo, wc)); + break; + + case V4L2_FRMSIZE_TYPE_STEPWISE: + { + __u32 width = Texture::up_to_power_2(frmsizeenum.stepwise.min_width); + for (; width <= frmsizeenum.stepwise.max_width; width *= 2) { + __u32 height = Texture::up_to_power_2(frmsizeenum.stepwise.min_height); + for (; height <= frmsizeenum.stepwise.max_height; height *= 2) { + if ((width - frmsizeenum.stepwise.min_width) % frmsizeenum.stepwise.step_width == 0 && + (height - frmsizeenum.stepwise.min_height) % frmsizeenum.stepwise.step_height == 0) { + WebcamVideoV4L:: + add_options_for_size(fd, *it, (const char *)cap2.card, width, height, fmt.pixelformat); + } + } + } } + break; } } } diff --git a/panda/src/vision/webcamVideoV4L.h b/panda/src/vision/webcamVideoV4L.h index 7ebf131df8..1405497fed 100644 --- a/panda/src/vision/webcamVideoV4L.h +++ b/panda/src/vision/webcamVideoV4L.h @@ -33,9 +33,12 @@ private: friend class WebcamVideoCursorV4L; friend void find_all_webcams_v4l(); + static void add_options_for_size(int fd, const string &dev, const char *name, + unsigned width, unsigned height, + unsigned pixelformat); string _device; - pvector _pformats; + uint32_t _pformat; public: static TypeHandle get_class_type() {