|
@@ -0,0 +1,177 @@
|
|
|
|
|
+// Filename: webcamVideoCursorOpenCV.cxx
|
|
|
|
|
+// Created by: drose (20Oct10)
|
|
|
|
|
+//
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+//
|
|
|
|
|
+// 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."
|
|
|
|
|
+//
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+
|
|
|
|
|
+#include "webcamVideoOpenCV.h"
|
|
|
|
|
+
|
|
|
|
|
+#ifdef HAVE_OPENCV
|
|
|
|
|
+
|
|
|
|
|
+#include "pStatTimer.h"
|
|
|
|
|
+
|
|
|
|
|
+TypeHandle WebcamVideoCursorOpenCV::_type_handle;
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: WebcamVideoCursorOpenCV::Constructor
|
|
|
|
|
+// Access: Published
|
|
|
|
|
+// Description:
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+WebcamVideoCursorOpenCV::
|
|
|
|
|
+WebcamVideoCursorOpenCV(WebcamVideoOpenCV *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;
|
|
|
|
|
+
|
|
|
|
|
+ _capture = cvCaptureFromCAM(src->_camera_index);
|
|
|
|
|
+ if (_capture != NULL) {
|
|
|
|
|
+ _size_x = (int)cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_WIDTH);
|
|
|
|
|
+ _size_y = (int)cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_HEIGHT);
|
|
|
|
|
+ _ready = true;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: WebcamVideoCursorOpenCV::Destructor
|
|
|
|
|
+// Access: Published, Virtual
|
|
|
|
|
+// Description:
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+WebcamVideoCursorOpenCV::
|
|
|
|
|
+~WebcamVideoCursorOpenCV() {
|
|
|
|
|
+ if (_capture != NULL) {
|
|
|
|
|
+ cvReleaseCapture(&_capture);
|
|
|
|
|
+ _capture = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: WebcamVideoCursorOpenCV::fetch_into_buffer
|
|
|
|
|
+// Access: Published, Virtual
|
|
|
|
|
+// Description:
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void WebcamVideoCursorOpenCV::
|
|
|
|
|
+fetch_into_buffer(double time, unsigned char *block, bool bgra) {
|
|
|
|
|
+ if (!_ready) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ unsigned char *dest = block;
|
|
|
|
|
+ int num_components = bgra ? 4 : 3;
|
|
|
|
|
+ ssize_t dest_x_pitch = num_components; // Assume component_width == 1
|
|
|
|
|
+ ssize_t dest_y_pitch = _size_x * dest_x_pitch;
|
|
|
|
|
+
|
|
|
|
|
+ const unsigned char *r, *g, *b;
|
|
|
|
|
+ ssize_t x_pitch, y_pitch;
|
|
|
|
|
+ if (get_frame_data(r, g, b, x_pitch, y_pitch)) {
|
|
|
|
|
+ if (num_components == 3 && x_pitch == 3) {
|
|
|
|
|
+ // The easy case--copy the whole thing in, row by row.
|
|
|
|
|
+ ssize_t copy_bytes = _size_x * dest_x_pitch;
|
|
|
|
|
+ nassertv(copy_bytes <= dest_y_pitch && copy_bytes <= abs(y_pitch));
|
|
|
|
|
+
|
|
|
|
|
+ for (int y = 0; y < _size_y; ++y) {
|
|
|
|
|
+ memcpy(dest, r, copy_bytes);
|
|
|
|
|
+ dest += dest_y_pitch;
|
|
|
|
|
+ r += y_pitch;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // The harder case--interleave in the color channels, pixel by
|
|
|
|
|
+ // pixel.
|
|
|
|
|
+
|
|
|
|
|
+ for (int y = 0; y < _size_y; ++y) {
|
|
|
|
|
+ ssize_t dx = 0;
|
|
|
|
|
+ ssize_t sx = 0;
|
|
|
|
|
+ for (int x = 0; x < _size_x; ++x) {
|
|
|
|
|
+ dest[dx] = r[sx];
|
|
|
|
|
+ dest[dx + 1] = g[sx];
|
|
|
|
|
+ dest[dx + 2] = b[sx];
|
|
|
|
|
+ dx += dest_x_pitch;
|
|
|
|
|
+ sx += x_pitch;
|
|
|
|
|
+ }
|
|
|
|
|
+ dest += dest_y_pitch;
|
|
|
|
|
+ r += y_pitch;
|
|
|
|
|
+ g += y_pitch;
|
|
|
|
|
+ b += y_pitch;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: WebcamVideoCursorOpenCV::get_frame_data
|
|
|
|
|
+// Access: Private
|
|
|
|
|
+// Description: Gets the data needed to traverse through the
|
|
|
|
|
+// decompressed buffer. Returns true on success, false
|
|
|
|
|
+// on failure.
|
|
|
|
|
+//
|
|
|
|
|
+// In the case of a success indication (true return
|
|
|
|
|
+// value), the three pointers r, g, b are loaded with
|
|
|
|
|
+// the addresses of the three components of the
|
|
|
|
|
+// bottom-left pixel of the image. (They will be
|
|
|
|
|
+// adjacent in memory in the case of an interleaved
|
|
|
|
|
+// image, and separated in the case of a
|
|
|
|
|
+// separate-channel image.) The x_pitch value is filled
|
|
|
|
|
+// with the amount to add to each pointer to advance to
|
|
|
|
|
+// the pixel to the right; and the y_pitch value is
|
|
|
|
|
+// filled with the amount to add to each pointer to
|
|
|
|
|
+// advance to the pixel above. Note that these values
|
|
|
|
|
+// may be negative (particularly in the case of a
|
|
|
|
|
+// top-down image).
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+bool WebcamVideoCursorOpenCV::
|
|
|
|
|
+get_frame_data(const unsigned char *&r,
|
|
|
|
|
+ const unsigned char *&g,
|
|
|
|
|
+ const unsigned char *&b,
|
|
|
|
|
+ ssize_t &x_pitch, ssize_t &y_pitch) {
|
|
|
|
|
+ nassertr(ready(), false);
|
|
|
|
|
+
|
|
|
|
|
+ IplImage *image = cvQueryFrame(_capture);
|
|
|
|
|
+ if (image == NULL) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ r = (const unsigned char *)image->imageData;
|
|
|
|
|
+ g = r + 1;
|
|
|
|
|
+ b = g + 1;
|
|
|
|
|
+ x_pitch = 3;
|
|
|
|
|
+ y_pitch = image->widthStep;
|
|
|
|
|
+
|
|
|
|
|
+ if (image->dataOrder == 1) {
|
|
|
|
|
+ // Separate channel images. That means a block of r, followed by
|
|
|
|
|
+ // a block of g, followed by a block of b.
|
|
|
|
|
+ x_pitch = 1;
|
|
|
|
|
+ g = r + image->height * y_pitch;
|
|
|
|
|
+ b = g + image->height * y_pitch;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (image->origin == 0) {
|
|
|
|
|
+ // The image data starts with the top row and ends with the bottom
|
|
|
|
|
+ // row--the opposite of Texture::_ram_data's storage convention.
|
|
|
|
|
+ // Therefore, we must increment the initial pointers to the last
|
|
|
|
|
+ // row, and count backwards.
|
|
|
|
|
+ r += (image->height - 1) * y_pitch;
|
|
|
|
|
+ g += (image->height - 1) * y_pitch;
|
|
|
|
|
+ b += (image->height - 1) * y_pitch;
|
|
|
|
|
+ y_pitch = -y_pitch;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#endif
|