Video4Linux2 support for WebcamVideo and a few minor improvements to the webcam code.
This commit is contained in:
parent
b709455d4e
commit
00ee003d1e
|
|
@ -9,26 +9,30 @@
|
|||
#define TARGET p3vision
|
||||
#define LOCAL_LIBS \
|
||||
display text pgraph gobj linmath putil audio movies
|
||||
|
||||
|
||||
#define COMBINED_SOURCES vision_composite1.cxx
|
||||
|
||||
#define SOURCES \
|
||||
arToolKit.I arToolKit.h \
|
||||
config_vision.h \
|
||||
openCVTexture.I openCVTexture.h \
|
||||
webcamVideo.h webcamVideo.I
|
||||
|
||||
webcamVideo.h webcamVideo.I \
|
||||
webcamVideoCursorV4L.h webcamVideoV4L.h
|
||||
|
||||
#define INCLUDED_SOURCES \
|
||||
arToolKit.cxx \
|
||||
config_vision.cxx \
|
||||
openCVTexture.cxx \
|
||||
webcamVideo.cxx \
|
||||
webcamVideoDS.cxx
|
||||
|
||||
webcamVideoDS.cxx \
|
||||
webcamVideoCursorV4L.cxx \
|
||||
webcamVideoV4L.cxx
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
arToolKit.I arToolKit.h \
|
||||
openCVTexture.I openCVTexture.h \
|
||||
webcamVideo.h webcamVideo.I
|
||||
webcamVideo.h webcamVideo.I \
|
||||
webcamVideoCursorV4L.h webcamVideoV4L.h
|
||||
|
||||
#define IGATESCAN all
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
#include "config_vision.h"
|
||||
#include "openCVTexture.h"
|
||||
#include "webcamVideo.h"
|
||||
#include "webcamVideoCursorV4L.h"
|
||||
#include "webcamVideoV4L.h"
|
||||
|
||||
#include "pandaSystem.h"
|
||||
#include "texturePool.h"
|
||||
|
|
@ -44,6 +46,8 @@ init_libvision() {
|
|||
initialized = true;
|
||||
|
||||
WebcamVideo::init_type();
|
||||
WebcamVideoCursorV4L::init_type();
|
||||
WebcamVideoV4L::init_type();
|
||||
|
||||
#ifdef HAVE_OPENCV
|
||||
OpenCVTexture::init_type();
|
||||
|
|
|
|||
|
|
@ -2,5 +2,7 @@
|
|||
#include "config_vision.cxx"
|
||||
#include "openCVTexture.cxx"
|
||||
#include "webcamVideo.cxx"
|
||||
#include "webcamVideoCursorV4L.cxx"
|
||||
#include "webcamVideoDS.cxx"
|
||||
#include "webcamVideoV4L.cxx"
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,27 @@ get_size_y() const {
|
|||
// Function: WebcamVideo::get_fps
|
||||
// Access: Published
|
||||
// Description: Returns the camera's framerate. This
|
||||
// is a maximum theoretical: the actual performance
|
||||
// is a maximum theoretical: the actual performance
|
||||
// will depend on the speed of the hardware.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int WebcamVideo::
|
||||
get_fps() const {
|
||||
return _fps;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideo::output
|
||||
// Access: Public
|
||||
// Description: Outputs the WebcamVideo. This function simply
|
||||
// writes the name, size and FPS to the output stream.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void WebcamVideo::
|
||||
output(ostream &out) const {
|
||||
out << get_name() << ": " << get_size_x() << "x" << get_size_y() << " @ " << get_fps() << "Hz";
|
||||
}
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const WebcamVideo &n) {
|
||||
n.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ TypeHandle WebcamVideo::_type_handle;
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideo::Destructor
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
WebcamVideo::
|
||||
~WebcamVideo() {
|
||||
|
|
@ -55,7 +55,7 @@ find_all_webcams() {
|
|||
find_all_webcams_ds();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VIDEO4LINUX
|
||||
#ifdef IS_LINUX
|
||||
extern void find_all_webcams_v4l();
|
||||
find_all_webcams_v4l();
|
||||
#endif
|
||||
|
|
@ -63,11 +63,11 @@ find_all_webcams() {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideo::get_num_options
|
||||
// Access: Public
|
||||
// Access: Public, Static
|
||||
// Description: Returns the number of webcam options. An "option"
|
||||
// consists of a device plus a set of configuration
|
||||
// parameters. For example, "Creative Webcam Live at
|
||||
// 640x480, 30 fps" is an option.
|
||||
// 640x480, 30 fps" is an option.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int WebcamVideo::
|
||||
get_num_options() {
|
||||
|
|
@ -77,7 +77,7 @@ get_num_options() {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideo::get_option
|
||||
// Access: Public
|
||||
// Access: Public, Static
|
||||
// Description: Returns the nth webcam option.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(WebcamVideo) WebcamVideo::
|
||||
|
|
|
|||
|
|
@ -30,13 +30,15 @@ PUBLISHED:
|
|||
static int get_num_options();
|
||||
static PT(WebcamVideo) get_option(int n);
|
||||
MAKE_SEQ(get_options, get_num_options, get_option);
|
||||
|
||||
|
||||
INLINE int get_size_x() const;
|
||||
INLINE int get_size_y() const;
|
||||
INLINE int get_fps() const;
|
||||
|
||||
|
||||
virtual PT(MovieVideoCursor) open() = 0;
|
||||
|
||||
INLINE void output(ostream &out) const;
|
||||
|
||||
public:
|
||||
static void find_all_webcams();
|
||||
|
||||
|
|
@ -65,6 +67,8 @@ private:
|
|||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const WebcamVideo &n);
|
||||
|
||||
#include "webcamVideo.I"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,413 @@
|
|||
// Filename: webcamVideoCursorV4L.cxx
|
||||
// Created by: rdb (11Jun2010)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef IS_LINUX
|
||||
|
||||
#include "webcamVideoV4L.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
extern "C" {
|
||||
#include <jpeglib.h>
|
||||
#include <jpegint.h>
|
||||
#include <jerror.h>
|
||||
}
|
||||
|
||||
#include <setjmp.h>
|
||||
#endif
|
||||
|
||||
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) {
|
||||
double y1 = (255 / 219.0) * (src[0] - 16);
|
||||
double pb = (255 / 224.0) * (src[1] - 128);
|
||||
double pr = (255 / 224.0) * (src[2] - 128);
|
||||
dest[2] = clamp(1.0 * y1 + 0 * pb + 1.402 * pr);
|
||||
dest[1] = clamp(1.0 * y1 - 0.344 * pb - 0.714 * pr);
|
||||
dest[0] = clamp(1.0 * y1 + 1.772 * pb + 0 * pr);
|
||||
}
|
||||
|
||||
INLINE static void yuyv_to_rgbrgb(unsigned char *dest, const unsigned char *src) {
|
||||
unsigned char yuv[] = {src[0], src[1], src[3]};
|
||||
yuv_to_rgb(dest, yuv);
|
||||
yuv[0] = src[2];
|
||||
yuv_to_rgb(dest + 3, yuv);
|
||||
}
|
||||
|
||||
INLINE static void yuyv_to_rgbargba(unsigned char *dest, const unsigned char *src) {
|
||||
unsigned char yuv[] = {src[0], src[1], src[3]};
|
||||
yuv_to_rgb(dest, yuv);
|
||||
yuv[0] = src[2];
|
||||
yuv_to_rgb(dest + 4, yuv);
|
||||
dest[3] = (unsigned char) -1;
|
||||
dest[7] = (unsigned char) -1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_JPEG) && !defined(CPPPARSER)
|
||||
|
||||
struct my_error_mgr {
|
||||
struct jpeg_error_mgr pub;
|
||||
jmp_buf setjmp_buffer;
|
||||
};
|
||||
|
||||
typedef struct my_error_mgr *my_error_ptr;
|
||||
|
||||
static void my_error_exit (j_common_ptr cinfo) {
|
||||
// Output the error message
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
(*cinfo->err->format_message) (cinfo, buffer);
|
||||
vision_cat.error() << buffer << "\n";
|
||||
// cinfo->err really points to a my_error_mgr struct, so coerce pointer
|
||||
my_error_ptr myerr = (my_error_ptr) cinfo->err;
|
||||
// Return control to the setjmp point
|
||||
longjmp(myerr->setjmp_buffer, 1);
|
||||
}
|
||||
|
||||
static void my_output_message (j_common_ptr cinfo){
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
(*cinfo->err->format_message) (cinfo, buffer);
|
||||
vision_cat.warning() << buffer << "\n";
|
||||
}
|
||||
|
||||
static void my_init_source(j_decompress_ptr cinfo) {
|
||||
}
|
||||
|
||||
static boolean my_fill_input_buffer(j_decompress_ptr cinfo) {
|
||||
struct jpeg_source_mgr *src = cinfo->src;
|
||||
static JOCTET FakeEOI[] = {0xFF, JPEG_EOI};
|
||||
|
||||
WARNMS(cinfo, JWRN_JPEG_EOF);
|
||||
|
||||
src->next_input_byte = FakeEOI;
|
||||
src->bytes_in_buffer = 2;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void my_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
|
||||
struct jpeg_source_mgr *src = cinfo->src;
|
||||
|
||||
if (num_bytes >= (long) src->bytes_in_buffer) {
|
||||
my_fill_input_buffer(cinfo);
|
||||
return;
|
||||
}
|
||||
|
||||
src->bytes_in_buffer -= num_bytes;
|
||||
src->next_input_byte += num_bytes;
|
||||
}
|
||||
|
||||
static void my_term_source(j_decompress_ptr cinfo) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoCursorV4L::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
WebcamVideoCursorV4L::
|
||||
WebcamVideoCursorV4L(WebcamVideoV4L *src) : MovieVideoCursor(src) {
|
||||
_size_x = src->_size_x;
|
||||
_size_y = src->_size_y;
|
||||
_num_components = 3;
|
||||
_length = 1.0E10;
|
||||
_can_seek = false;
|
||||
_can_seek_fast = false;
|
||||
_aborted = false;
|
||||
_last_start = -1.0;
|
||||
_next_start = 0.0;
|
||||
_streaming = true;
|
||||
_ready = false;
|
||||
_format = (struct v4l2_format *) malloc(sizeof(struct v4l2_format));
|
||||
memset(_format, 0, sizeof(struct v4l2_format));
|
||||
_cinfo = NULL;
|
||||
_buffers = NULL;
|
||||
_buflens = NULL;
|
||||
_fd = open(src->_device.c_str(), O_RDWR);
|
||||
if (-1 == _fd) {
|
||||
vision_cat.error() << "Failed to open " << src->_device.c_str() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
pvector<uint32_t>::iterator it;
|
||||
for (it = src->_pformats.begin(); it != src->_pformats.end(); ++it) {
|
||||
#ifdef HAVE_JPEG
|
||||
if (*it == V4L2_PIX_FMT_MJPEG) {
|
||||
_format->fmt.pix.pixelformat = *it;
|
||||
break;
|
||||
} else
|
||||
#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";
|
||||
_ready = false;
|
||||
close(_fd);
|
||||
_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// No interlacing
|
||||
_format->fmt.pix.field = V4L2_FIELD_NONE;
|
||||
|
||||
// This really should be there, but for
|
||||
// some reason it causes weird memory corruption.
|
||||
|
||||
_format->fmt.pix.width = _size_x;
|
||||
_format->fmt.pix.height = _size_y;
|
||||
|
||||
// Now politely ask the driver to switch to this format
|
||||
if (-1 == ioctl(_fd, VIDIOC_S_FMT, _format)) {
|
||||
vision_cat.error() << "Driver rejected format!\n";
|
||||
_ready = false;
|
||||
close(_fd);
|
||||
_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
_size_x = _format->fmt.pix.width;
|
||||
_size_y = _format->fmt.pix.height;
|
||||
|
||||
struct v4l2_requestbuffers req;
|
||||
memset(&req, 0, sizeof req);
|
||||
req.count = 4;
|
||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (-1 == ioctl (_fd, VIDIOC_REQBUFS, &req)) {
|
||||
vision_cat.error() << "Failed to request buffers from webcam!\n";
|
||||
}
|
||||
|
||||
if (req.count < 2) {
|
||||
vision_cat.error() << "Insufficient buffer memory!\n";
|
||||
}
|
||||
|
||||
_bufcount = req.count;
|
||||
_buffers = (void* *) calloc (req.count, sizeof (void*));
|
||||
_buflens = (size_t*) calloc (req.count, sizeof (size_t));
|
||||
|
||||
if (!_buffers || !_buflens) {
|
||||
vision_cat.error() << "Not enough memory!\n";
|
||||
}
|
||||
|
||||
struct v4l2_buffer buf;
|
||||
for (int i = 0; i < _bufcount; ++i) {
|
||||
memset(&buf, 0, sizeof buf);
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
|
||||
if (-1 == ioctl(_fd, VIDIOC_QUERYBUF, &buf)) {
|
||||
vision_cat.error() << "Failed to query buffer!\n";
|
||||
}
|
||||
|
||||
_buflens[i] = buf.length;
|
||||
_buffers[i] = mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, buf.m.offset);
|
||||
|
||||
if (_buffers[i] == MAP_FAILED) {
|
||||
vision_cat.error() << "Failed to map buffer!\n";
|
||||
}
|
||||
|
||||
if (-1 == ioctl(_fd, VIDIOC_QBUF, &buf)) {
|
||||
vision_cat.error() << "Failed to exchange buffer with driver!\n";
|
||||
}
|
||||
}
|
||||
|
||||
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (-1 == ioctl(_fd, VIDIOC_STREAMON, &type)) {
|
||||
vision_cat.error() << "Failed to stream from buffer!\n";
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
_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;
|
||||
}
|
||||
#endif
|
||||
_ready = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoCursorV4L::Destructor
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
WebcamVideoCursorV4L::
|
||||
~WebcamVideoCursorV4L() {
|
||||
#ifdef HAVE_JPEG
|
||||
if (_cinfo != NULL) {
|
||||
jpeg_destroy_decompress(_cinfo);
|
||||
free(_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);
|
||||
close(_fd);
|
||||
}
|
||||
if (_buffers) {
|
||||
for (int i = 0; i < _bufcount; ++i) {
|
||||
munmap(_buffers[i], _buflens[i]);
|
||||
}
|
||||
free(_buffers);
|
||||
}
|
||||
if (_buflens) {
|
||||
free(_buflens);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoCursorV4L::fetch_into_buffer
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void WebcamVideoCursorV4L::
|
||||
fetch_into_buffer(double time, unsigned char *block, bool bgra) {
|
||||
if (!_ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct v4l2_buffer vbuf;
|
||||
memset(&vbuf, 0, sizeof vbuf);
|
||||
vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
vbuf.memory = V4L2_MEMORY_MMAP;
|
||||
if (-1 == ioctl(_fd, VIDIOC_DQBUF, &vbuf) && errno != EIO) {
|
||||
vision_cat.error() << "Failed to dequeue buffer!\n";
|
||||
return;
|
||||
}
|
||||
nassertv(vbuf.index < _bufcount);
|
||||
size_t bufsize = _buflens[vbuf.index];
|
||||
size_t old_bpl = _format->fmt.pix.bytesperline;
|
||||
size_t new_bpl = bgra ? _size_x * 4 : _size_x * 3;
|
||||
unsigned char *buf = (unsigned char *) _buffers[vbuf.index];
|
||||
|
||||
if (_format->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
|
||||
#ifdef HAVE_JPEG
|
||||
nassertv(!bgra);
|
||||
struct my_error_mgr jerr;
|
||||
_cinfo->err = jpeg_std_error(&jerr.pub);
|
||||
jerr.pub.error_exit = my_error_exit;
|
||||
jerr.pub.output_message = my_output_message;
|
||||
|
||||
unsigned char *newbuf = (unsigned char*) malloc(new_bpl * _size_y);
|
||||
|
||||
// Establish the setjmp return context for my_error_exit to use
|
||||
if (setjmp(jerr.setjmp_buffer)) {
|
||||
if (_cinfo->global_state > DSTATE_READY) {
|
||||
jpeg_abort_decompress(_cinfo);
|
||||
}
|
||||
} else {
|
||||
// Set up data pointer
|
||||
_cinfo->src->bytes_in_buffer = bufsize;
|
||||
_cinfo->src->next_input_byte = buf;
|
||||
|
||||
if (jpeg_read_header(_cinfo, TRUE) == JPEG_HEADER_OK) {
|
||||
_cinfo->scale_num = 1;
|
||||
_cinfo->scale_denom = 1;
|
||||
_cinfo->out_color_space = JCS_RGB;
|
||||
|
||||
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 *rowptr = newbuf;
|
||||
while (_cinfo->output_scanline < _cinfo->output_height) {
|
||||
nassertd(rowptr + new_bpl <= buffer_end) break;
|
||||
jpeg_read_scanlines(_cinfo, &rowptr, 1);
|
||||
rowptr += new_bpl;
|
||||
}
|
||||
|
||||
if (_cinfo->output_scanline < _cinfo->output_height) {
|
||||
jpeg_abort_decompress(_cinfo);
|
||||
} else {
|
||||
jpeg_finish_decompress(_cinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flip the image vertically
|
||||
for (size_t row = 0; row < _size_y; ++row) {
|
||||
memcpy(block + (_size_y - row - 1) * new_bpl, newbuf + row * new_bpl, new_bpl);
|
||||
}
|
||||
free(newbuf);
|
||||
|
||||
// Swap red / blue
|
||||
unsigned char ex;
|
||||
if (bgra) {
|
||||
for (size_t i = 0; i < new_bpl * _size_y; i += 4) {
|
||||
ex = block[i];
|
||||
block[i] = block[i + 2];
|
||||
block[i + 2] = ex;
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < new_bpl * _size_y; i += 3) {
|
||||
ex = block[i];
|
||||
block[i] = block[i + 2];
|
||||
block[i + 2] = ex;
|
||||
}
|
||||
}
|
||||
#else
|
||||
nassertv(false); // Not compiled with JPEG support
|
||||
#endif
|
||||
} else {
|
||||
if (bgra) {
|
||||
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_rgbargba(block + (_size_y - row - 1) * new_bpl + c, buf + row * old_bpl + i);
|
||||
c += 8;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
c += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-1 == ioctl(_fd, VIDIOC_QBUF, &vbuf)) {
|
||||
vision_cat.error() << "Failed to exchange buffer with driver!\n";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// Filename: webcamVideoCursorV4L.h
|
||||
// Created by: rdb (11Jun2010)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef WEBCAMVIDEOCURSORV4L_H
|
||||
#define WEBCAMVIDEOCURSORV4L_H
|
||||
|
||||
#ifdef IS_LINUX
|
||||
|
||||
#include "webcamVideo.h"
|
||||
|
||||
struct v4l2_format;
|
||||
#ifdef HAVE_JPEG
|
||||
struct jpeg_decompress_struct;
|
||||
#endif
|
||||
|
||||
class WebcamVideoV4L;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : WebcamVideoCursorV4L
|
||||
// Description : The Video4Linux implementation of webcams.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class WebcamVideoCursorV4L : public MovieVideoCursor {
|
||||
public:
|
||||
WebcamVideoCursorV4L(WebcamVideoV4L *src);
|
||||
virtual ~WebcamVideoCursorV4L();
|
||||
virtual void fetch_into_buffer(double time, unsigned char *block, bool rgba);
|
||||
|
||||
private:
|
||||
int _fd;
|
||||
void **_buffers;
|
||||
size_t *_buflens;
|
||||
size_t _bufcount;
|
||||
struct v4l2_format *_format;
|
||||
#ifdef HAVE_JPEG
|
||||
struct jpeg_decompress_struct *_cinfo;
|
||||
#endif
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
MovieVideoCursor::init_type();
|
||||
register_type(_type_handle, "WebcamVideoCursorV4L",
|
||||
MovieVideoCursor::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#endif // IS_LINUX
|
||||
|
||||
#endif
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
// This code was created by studying and adapting the VDOGRAB
|
||||
// library by Shu-Kai Yang and the videoInput library by Theodore
|
||||
// Watson. We owe both of them a great deal of thanks for
|
||||
// figuring all this out. Both of their libraries have
|
||||
// figuring all this out. Both of their libraries have
|
||||
// informal licenses (the "do whatever you want and don't blame
|
||||
// me" sort), so I think there's not a problem using their code.
|
||||
//
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
#ifdef HAVE_DIRECTCAM
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#undef Configure
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ private:
|
|||
|
||||
IMoniker *_moniker;
|
||||
AM_MEDIA_TYPE *_media;
|
||||
|
||||
|
||||
friend class WebcamVideoCursorDS;
|
||||
|
||||
public:
|
||||
|
|
@ -141,14 +141,14 @@ public:
|
|||
public:
|
||||
void cleanup();
|
||||
|
||||
class CSampleGrabberCB : public ISampleGrabberCB
|
||||
{
|
||||
class CSampleGrabberCB : public ISampleGrabberCB
|
||||
{
|
||||
public:
|
||||
WebcamVideoCursorDS *_host;
|
||||
|
||||
|
||||
ULONG __stdcall AddRef() { return 2; }
|
||||
ULONG __stdcall Release() { return 1; }
|
||||
|
||||
|
||||
HRESULT __stdcall QueryInterface(REFIID riid, void ** ppv);
|
||||
HRESULT __stdcall SampleCB(double SampleTime, IMediaSample *pSample);
|
||||
HRESULT __stdcall BufferCB(double dblSampleTime, BYTE *pBuffer, long lBufferSize);
|
||||
|
|
@ -161,12 +161,12 @@ public:
|
|||
ICaptureGraphBuilder2 *_pCaptureBuilder;
|
||||
IBaseFilter *_pSrcFilter;
|
||||
IAMStreamConfig *_pStreamConfig;
|
||||
CComPtr<ISampleGrabber> _pSampleGrabber;
|
||||
CComPtr<ISampleGrabber> _pSampleGrabber;
|
||||
IBaseFilter *_pStreamRenderer;
|
||||
IMediaControl *_pMediaCtrl;
|
||||
// IMemAllocator *_pAllocator;
|
||||
CSampleGrabberCB _sample_cb;
|
||||
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
|
|
@ -329,30 +329,28 @@ add_device(WebcamVideoList &list, IMoniker *pMoniker, AM_MEDIA_TYPE *media) {
|
|||
}
|
||||
}
|
||||
PT(WebcamVideoDS) wc = new WebcamVideoDS;
|
||||
ostringstream name;
|
||||
name << "DirectShow: " << get_moniker_name(pMoniker) << " @ " << media_x(media) << " x " << media_y(media) << " FPS:" << media_fps(media);
|
||||
wc->set_name(name.str());
|
||||
wc->set_name(get_moniker_name(pMoniker));
|
||||
wc->_size_x = media_x(media);
|
||||
wc->_size_y = media_y(media);
|
||||
wc->_fps = media_fps(media);
|
||||
wc->_moniker = pMoniker;
|
||||
wc->_media = media;
|
||||
list.push_back(wc);
|
||||
cerr << "Added device: " << wc->get_name() << "\n";
|
||||
cerr << "Added device: DirectShow: " << wc << "\n";
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoDS::find_all_webcams_ds
|
||||
// Access: Public, Static
|
||||
// Description: Finds all DirectShow webcams and adds them to
|
||||
// Description: Finds all DirectShow webcams and adds them to
|
||||
// the global list _all_webcams.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void WebcamVideoDS::
|
||||
find_all_webcams_ds() {
|
||||
|
||||
pvector <PT(WebcamVideoDS)> list;
|
||||
|
||||
|
||||
ICreateDevEnum *pCreateDevEnum=NULL;
|
||||
IEnumMoniker *pEnumMoniker=NULL;
|
||||
IGraphBuilder *pGraphBuilder=NULL;
|
||||
|
|
@ -362,7 +360,7 @@ find_all_webcams_ds() {
|
|||
IAMStreamConfig *pStreamConfig=NULL;
|
||||
HRESULT hResult;
|
||||
ULONG cFetched;
|
||||
|
||||
|
||||
hResult=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
|
||||
IID_IGraphBuilder,(void**)&pGraphBuilder);
|
||||
if (hResult != S_OK) goto cleanup;
|
||||
|
|
@ -377,7 +375,7 @@ find_all_webcams_ds() {
|
|||
hResult=pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
|
||||
&pEnumMoniker, 0);
|
||||
if(hResult != S_OK) goto cleanup;
|
||||
|
||||
|
||||
while(1) {
|
||||
if (pMoniker) { pMoniker->Release(); pMoniker=0; }
|
||||
if (pBaseFilter) { pBaseFilter->Release(); pBaseFilter=0; }
|
||||
|
|
@ -390,7 +388,7 @@ find_all_webcams_ds() {
|
|||
if (hResult != S_OK) continue;
|
||||
hResult = pCaptureGraphBuilder2->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pBaseFilter,
|
||||
IID_IAMStreamConfig, (void **)&pStreamConfig);
|
||||
if (hResult != S_OK) continue;
|
||||
if (hResult != S_OK) continue;
|
||||
int iCount, iSize;
|
||||
hResult = pStreamConfig->GetNumberOfCapabilities(&iCount, &iSize);
|
||||
if (hResult != S_OK || (iSize != sizeof(VIDEO_STREAM_CONFIG_CAPS))) continue;
|
||||
|
|
@ -405,10 +403,10 @@ find_all_webcams_ds() {
|
|||
add_device(list, pMoniker, mtype);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pMoniker = 0;
|
||||
}
|
||||
|
||||
|
||||
cleanup:
|
||||
if (pCreateDevEnum) { pCreateDevEnum->Release(); pCreateDevEnum=0; }
|
||||
if (pEnumMoniker) { pEnumMoniker->Release(); pEnumMoniker=0; }
|
||||
|
|
@ -417,7 +415,7 @@ find_all_webcams_ds() {
|
|||
if (pMoniker) { pMoniker->Release(); pMoniker=0; }
|
||||
if (pBaseFilter) { pBaseFilter->Release(); pBaseFilter=0; }
|
||||
if (pStreamConfig) { pStreamConfig->Release(); pStreamConfig=0; }
|
||||
|
||||
|
||||
for (int i=0; i<(int)list.size(); i++) {
|
||||
WebcamVideoDS *obj = list[i];
|
||||
_all_webcams.push_back(obj);
|
||||
|
|
@ -443,7 +441,7 @@ open() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoCursorDS::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
WebcamVideoCursorDS::
|
||||
WebcamVideoCursorDS(WebcamVideoDS *src) :
|
||||
|
|
@ -457,39 +455,39 @@ WebcamVideoCursorDS(WebcamVideoDS *src) :
|
|||
{
|
||||
AM_MEDIA_TYPE mediaType;
|
||||
VIDEOINFOHEADER *pVideoInfo;
|
||||
|
||||
|
||||
HRESULT hResult;
|
||||
|
||||
|
||||
hResult=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
|
||||
IID_IGraphBuilder,(void**)&_pGraphBuilder);
|
||||
if(hResult != S_OK) { cleanup(); return; }
|
||||
|
||||
|
||||
hResult=CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
|
||||
IID_ICaptureGraphBuilder2, (void**)&_pCaptureBuilder);
|
||||
if(hResult != S_OK) { cleanup(); return; }
|
||||
|
||||
|
||||
_pCaptureBuilder->SetFiltergraph(_pGraphBuilder);
|
||||
cerr << " IID_IGraphBuilder & IID_ICaptureGraphBuilder2 are established.\n";
|
||||
|
||||
|
||||
hResult=_pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&_pMediaCtrl);
|
||||
if(hResult != S_OK)
|
||||
{ cerr << " Can not get the IID_IMediaControl interface!";
|
||||
cleanup(); return; }
|
||||
cerr << " IID_IMediaControl interface is acquired.\n";
|
||||
|
||||
|
||||
src->_moniker->BindToObject(NULL,NULL,IID_IBaseFilter, (void**)&_pSrcFilter);
|
||||
if(_pSrcFilter == NULL)
|
||||
{ cerr << " Such capture device is not found.\n";
|
||||
cleanup(); return; }
|
||||
cerr << " The capture filter is acquired.\n";
|
||||
|
||||
|
||||
hResult=_pGraphBuilder->AddFilter(_pSrcFilter, L"Capture Filter");
|
||||
if(hResult != DD_OK)
|
||||
{ cerr << " The capture filter can not be added to the graph.\n";
|
||||
cleanup(); return; }
|
||||
cerr << " The capture filter has been added to the graph.\n";
|
||||
|
||||
|
||||
|
||||
|
||||
hResult = _pCaptureBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, _pSrcFilter,
|
||||
IID_IAMStreamConfig, (void **)&_pStreamConfig);
|
||||
if (hResult != S_OK) {
|
||||
|
|
@ -501,16 +499,16 @@ WebcamVideoCursorDS(WebcamVideoDS *src) :
|
|||
cerr << "Could not select desired video resolution\n";
|
||||
cleanup(); return;
|
||||
}
|
||||
|
||||
|
||||
_pSampleGrabber.CoCreateInstance(CLSID_SampleGrabber);
|
||||
if(!_pSampleGrabber)
|
||||
{ cerr << " Can not create the sample grabber, maybe qedit.dll is not registered?";
|
||||
cleanup(); return; }
|
||||
|
||||
|
||||
|
||||
|
||||
CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabberFilter(_pSampleGrabber);
|
||||
cerr << " IID_IBaseFilter of CLSID_SampleGrabber is acquired.\n";
|
||||
|
||||
|
||||
ZeroMemory(&mediaType, sizeof(AM_MEDIA_TYPE));
|
||||
mediaType.majortype=MEDIATYPE_Video;
|
||||
mediaType.subtype=MEDIASUBTYPE_RGB24;
|
||||
|
|
@ -519,14 +517,14 @@ WebcamVideoCursorDS(WebcamVideoDS *src) :
|
|||
{ cerr << " Fail to set the media type!";
|
||||
cleanup(); return; }
|
||||
cerr << " The media type of the sample grabber is set 24-bit RGB.\n";
|
||||
|
||||
|
||||
hResult=_pGraphBuilder->AddFilter(pGrabberFilter, L"Sample Grabber");
|
||||
if(hResult != S_OK)
|
||||
{ cerr << " Fail to add the sample grabber to the graph.";
|
||||
cleanup(); return; }
|
||||
cerr << " The sample grabber has been added to the graph.\n";
|
||||
|
||||
//used to give the video stream somewhere to go to.
|
||||
//used to give the video stream somewhere to go to.
|
||||
hResult = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&_pStreamRenderer);
|
||||
if(hResult != S_OK)
|
||||
{ cerr << " Can not create the null renderer.";
|
||||
|
|
@ -538,20 +536,20 @@ WebcamVideoCursorDS(WebcamVideoDS *src) :
|
|||
{ cerr << " Fail to add the Null Renderer to the graph.";
|
||||
cleanup(); return; }
|
||||
cerr << " The Null Renderer has been added to the graph.\n";
|
||||
|
||||
|
||||
hResult=_pCaptureBuilder->RenderStream(&PIN_CATEGORY_CAPTURE,
|
||||
&MEDIATYPE_Video, _pSrcFilter, pGrabberFilter, _pStreamRenderer);
|
||||
if(hResult != S_OK) {
|
||||
cerr << " ICaptureGraphBuilder2::RenderStream() can not connect the pins\n";
|
||||
cleanup(); return;
|
||||
}
|
||||
|
||||
|
||||
hResult=_pSampleGrabber->GetConnectedMediaType(&mediaType);
|
||||
if(hResult != S_OK) {
|
||||
cerr << " Failed to read the connected media type.";
|
||||
cleanup(); return;
|
||||
cleanup(); return;
|
||||
}
|
||||
|
||||
|
||||
// IPin *iPin;
|
||||
// hResult = FindInputPin(pGrabberFilter, &iPin);
|
||||
// if ((iPin == 0)||(hResult != S_OK)) {
|
||||
|
|
@ -579,12 +577,12 @@ WebcamVideoCursorDS(WebcamVideoDS *src) :
|
|||
// cerr << "Could not set allocator properties.\n";
|
||||
// }
|
||||
// cerr << "Allocator properties (adjusted): cBuffers=" << aprops.cBuffers << "\n";
|
||||
|
||||
|
||||
pVideoInfo=(VIDEOINFOHEADER*)mediaType.pbFormat;
|
||||
_size_x = pVideoInfo->bmiHeader.biWidth;
|
||||
_size_y = pVideoInfo->bmiHeader.biHeight;
|
||||
cerr << "Connected media type " << _size_x << " x " << _size_y << "\n";
|
||||
|
||||
|
||||
_sample_cb._host = this;
|
||||
_num_components = 3;
|
||||
_length = 1.0E10;
|
||||
|
|
@ -602,28 +600,28 @@ WebcamVideoCursorDS(WebcamVideoDS *src) :
|
|||
mediaType.cbFormat=0;
|
||||
mediaType.pbFormat=NULL;
|
||||
}
|
||||
|
||||
|
||||
if(mediaType.pUnk != NULL) {
|
||||
mediaType.pUnk->Release();
|
||||
mediaType.pUnk=NULL;
|
||||
}
|
||||
|
||||
|
||||
_pSampleGrabber->SetBufferSamples(FALSE);
|
||||
_pSampleGrabber->SetOneShot(FALSE);
|
||||
|
||||
|
||||
hResult=_pSampleGrabber->SetCallback(&_sample_cb, 0);
|
||||
if(hResult != S_OK) {
|
||||
cerr << " Can not set the callback interface!";
|
||||
cleanup(); return;
|
||||
}
|
||||
|
||||
|
||||
_pMediaCtrl->Run();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoCursorDS::cleanup
|
||||
// Access: Published
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void WebcamVideoCursorDS::
|
||||
cleanup() {
|
||||
|
|
@ -635,7 +633,7 @@ cleanup() {
|
|||
if (_pMediaCtrl) {
|
||||
_pMediaCtrl->Stop();
|
||||
}
|
||||
|
||||
|
||||
if(_pMediaCtrl) { _pMediaCtrl->Release(); _pMediaCtrl=NULL; }
|
||||
if(_pCaptureBuilder) { _pCaptureBuilder->Release(); _pCaptureBuilder=NULL; }
|
||||
if(_pGraphBuilder) { _pGraphBuilder->Release(); _pGraphBuilder=NULL; }
|
||||
|
|
@ -648,7 +646,7 @@ cleanup() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoCursorDS::Destructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
WebcamVideoCursorDS::
|
||||
~WebcamVideoCursorDS() {
|
||||
|
|
@ -658,16 +656,16 @@ WebcamVideoCursorDS::
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoCursorDS::fetch_into_buffer
|
||||
// Access: Published
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void WebcamVideoCursorDS::
|
||||
fetch_into_buffer(double time, unsigned char *block, bool bgra) {
|
||||
|
||||
|
||||
if (!_ready) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LOCKING_MODE
|
||||
#ifdef LOCKING_MODE
|
||||
unsigned char *ptr;
|
||||
int pixels = _size_x * _size_y;
|
||||
HRESULT res = _saved->GetPointer(&ptr);
|
||||
|
|
@ -700,7 +698,7 @@ fetch_into_buffer(double time, unsigned char *block, bool bgra) {
|
|||
memcpy(block, _buffer, pixels * 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
_ready = false;
|
||||
}
|
||||
|
||||
|
|
@ -708,14 +706,14 @@ fetch_into_buffer(double time, unsigned char *block, bool bgra) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoCursorDS::CSampleGrabberCB::QueryInterface
|
||||
// Access: Private
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::QueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
if((riid == IID_ISampleGrabberCB) || (riid == IID_IUnknown)) {
|
||||
*ppv=(void *)static_cast<ISampleGrabberCB *> (this);
|
||||
return NOERROR;
|
||||
}
|
||||
}
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
|
@ -723,7 +721,7 @@ HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::QueryInterface(REFIID r
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoCursorDS::CSampleGrabberCB::SampleCB
|
||||
// Access: Private
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::SampleCB(double SampleTime, IMediaSample *pSample)
|
||||
{
|
||||
|
|
@ -731,7 +729,7 @@ HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::SampleCB(double SampleT
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LOCKING_MODE
|
||||
#ifdef LOCKING_MODE
|
||||
pSample->AddRef();
|
||||
_host->_saved = pSample;
|
||||
#else
|
||||
|
|
@ -753,10 +751,10 @@ HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::SampleCB(double SampleT
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoCursorDS::CSampleGrabberCB::BufferCB
|
||||
// Access: Private
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::BufferCB(double dblSampleTime, BYTE *pBuffer, long lBufferSize)
|
||||
{
|
||||
{
|
||||
// Not used.
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -765,7 +763,7 @@ HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::BufferCB(double dblSamp
|
|||
//{
|
||||
// if (!pFilter || ! ppPin)
|
||||
// return E_POINTER;
|
||||
//
|
||||
//
|
||||
// *ppPin = 0;
|
||||
// HRESULT hr;
|
||||
// //Find the output pin of the Source Filter
|
||||
|
|
@ -773,7 +771,7 @@ HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::BufferCB(double dblSamp
|
|||
// hr = pFilter->EnumPins(&pPinEnum);
|
||||
// if (FAILED(hr))
|
||||
// return E_FAIL;
|
||||
//
|
||||
//
|
||||
// IPin *pSearchPin;
|
||||
// while (pPinEnum->Next(1, &pSearchPin, NULL) == S_OK)
|
||||
// {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,135 @@
|
|||
// Filename: webcamVideoV4L.cxx
|
||||
// Created by: rdb (11Jun2010)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef IS_LINUX
|
||||
|
||||
#include "webcamVideoV4L.h"
|
||||
#include "webcamVideoCursorV4L.h"
|
||||
|
||||
#include <linux/videodev.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
TypeHandle WebcamVideoV4L::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: find_all_webcams_v4l
|
||||
// Access: Public, Static
|
||||
// Description: Finds all Video4Linux webcams and adds them to
|
||||
// the global list _all_webcams.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void find_all_webcams_v4l() {
|
||||
struct video_capability cap;
|
||||
struct v4l2_capability cap2;
|
||||
|
||||
vector_string devs;
|
||||
GlobPattern pattern ("/dev/video*");
|
||||
pattern.match_files(devs);
|
||||
for (vector_string::iterator it = devs.begin(); it != devs.end(); ++it) {
|
||||
int fd = open(it->c_str(), O_RDWR);
|
||||
if (fd != -1) {
|
||||
// Check for Video4Linux2 capabilities
|
||||
if (ioctl(fd, VIDIOC_QUERYCAP, &cap2) != -1) {
|
||||
if ((cap2.capabilities & V4L2_CAP_VIDEO_CAPTURE) &&
|
||||
(cap2.capabilities & V4L2_CAP_STREAMING)) {
|
||||
struct v4l2_fmtdesc fmt;
|
||||
for (int i = 0;; i++) {
|
||||
memset(&fmt, 0, sizeof fmt);
|
||||
fmt.index = i;
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == -1) {
|
||||
break;
|
||||
}
|
||||
struct v4l2_frmsizeenum frmsizeenum;
|
||||
for (int j = 0;; j++) {
|
||||
memset(&frmsizeenum, 0, sizeof frmsizeenum);
|
||||
frmsizeenum.index = j;
|
||||
frmsizeenum.pixel_format = fmt.pixelformat;
|
||||
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);
|
||||
|
||||
// Iterate through the webcams to make sure we don't put any duplicates in there
|
||||
pvector<PT(WebcamVideo)>::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;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for Video4Linux capabilities
|
||||
if (ioctl(fd, VIDIOCGCAP, &cap) != -1) {
|
||||
if (cap.type & VID_TYPE_CAPTURE) {
|
||||
//TODO: Video4Linux support
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: WebcamVideoV4L::open
|
||||
// Access: Published, Virtual
|
||||
// Description: Open this video, returning a MovieVideoCursor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(MovieVideoCursor) WebcamVideoV4L::
|
||||
open() {
|
||||
return new WebcamVideoCursorV4L(this);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// Filename: webcamVideoV4L.h
|
||||
// Created by: rdb (11Jun2010)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef WEBCAMVIDEOV4L_H
|
||||
#define WEBCAMVIDEOV4L_H
|
||||
|
||||
#ifdef IS_LINUX
|
||||
|
||||
#include "webcamVideo.h"
|
||||
|
||||
class WebcamVideoCursorV4L;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : WebcamVideoV4L
|
||||
// Description : The Video4Linux implementation of webcams.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class WebcamVideoV4L : public WebcamVideo {
|
||||
private:
|
||||
virtual PT(MovieVideoCursor) open();
|
||||
|
||||
friend class WebcamVideoCursorV4L;
|
||||
friend void find_all_webcams_v4l();
|
||||
|
||||
string _device;
|
||||
pvector<uint32_t> _pformats;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
WebcamVideo::init_type();
|
||||
register_type(_type_handle, "WebcamVideoV4L",
|
||||
WebcamVideo::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#endif // IS_LINUX
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue