Panda3D

openCVTexture.cxx

00001 // Filename: openCVTexture.cxx
00002 // Created by:  zacpavlov (19Aug05)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "pandabase.h"
00016 
00017 #ifdef HAVE_OPENCV
00018 #include "openCVTexture.h"
00019 #include "clockObject.h"
00020 #include "config_gobj.h"
00021 #include "config_vision.h"
00022 #include "bamReader.h"
00023 #include "bamCacheRecord.h"
00024 
00025 TypeHandle OpenCVTexture::_type_handle;
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: OpenCVTexture::Constructor
00029 //       Access: Published
00030 //  Description: Sets up the texture to read frames from a camera
00031 ////////////////////////////////////////////////////////////////////
00032 OpenCVTexture::
00033 OpenCVTexture(const string &name) : 
00034   VideoTexture(name) 
00035 {
00036 }
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: OpenCVTexture::Copy Constructor
00040 //       Access: Protected
00041 //  Description: Use OpenCVTexture::make_copy() to make a duplicate copy of
00042 //               an existing OpenCVTexture.
00043 ////////////////////////////////////////////////////////////////////
00044 OpenCVTexture::
00045 OpenCVTexture(const OpenCVTexture &copy) : 
00046   VideoTexture(copy),
00047   _pages(copy._pages)
00048 {
00049   nassertv(false);
00050 }
00051 
00052 ////////////////////////////////////////////////////////////////////
00053 //     Function: OpenCVTexture::Destructor
00054 //       Access: Published, Virtual
00055 //  Description: 
00056 ////////////////////////////////////////////////////////////////////
00057 OpenCVTexture::
00058 ~OpenCVTexture() {
00059 }
00060 
00061 ////////////////////////////////////////////////////////////////////
00062 //     Function: OpenCVTexture::consider_update
00063 //       Access: Protected, Virtual
00064 //  Description: Calls update_frame() if the current frame has
00065 //               changed.
00066 ////////////////////////////////////////////////////////////////////
00067 void OpenCVTexture::
00068 consider_update() {
00069   int this_frame = ClockObject::get_global_clock()->get_frame_count();
00070   if (this_frame != _last_frame_update) {
00071     int frame = get_frame();
00072     if (_current_frame != frame) {
00073       update_frame(frame);
00074       _current_frame = frame;
00075     } else {
00076       // Loop through the pages to see if there's any camera stream to update.
00077       int max_z = max(_z_size, (int)_pages.size());
00078       for (int z = 0; z < max_z; ++z) {
00079         VideoPage &page = _pages[z];
00080         if (!page._color.is_from_file() || !page._alpha.is_from_file()) {
00081           update_frame(frame, z);
00082         }
00083       }
00084     }
00085     _last_frame_update = this_frame;
00086   }
00087 }
00088 
00089 ////////////////////////////////////////////////////////////////////
00090 //     Function: OpenCVTexture::do_make_copy
00091 //       Access: Protected, Virtual
00092 //  Description: Returns a new copy of the same Texture.  This copy,
00093 //               if applied to geometry, will be copied into texture
00094 //               as a separate texture from the original, so it will
00095 //               be duplicated in texture memory (and may be
00096 //               independently modified if desired).
00097 //               
00098 //               If the Texture is an OpenCVTexture, the resulting
00099 //               duplicate may be animated independently of the
00100 //               original.
00101 ////////////////////////////////////////////////////////////////////
00102 PT(Texture) OpenCVTexture::
00103 do_make_copy() {
00104   PT(OpenCVTexture) tex = new OpenCVTexture(get_name());
00105   tex->do_assign(*this);
00106 
00107   return tex.p();
00108 }
00109 
00110 ////////////////////////////////////////////////////////////////////
00111 //     Function: OpenCVTexture::do_assign
00112 //       Access: Protected
00113 //  Description: Implements make_copy().
00114 ////////////////////////////////////////////////////////////////////
00115 void OpenCVTexture::
00116 do_assign(const OpenCVTexture &copy) {
00117   VideoTexture::do_assign(copy);
00118   _pages = copy._pages;
00119 }
00120 
00121 ////////////////////////////////////////////////////////////////////
00122 //     Function: OpenCVTexture::from_camera
00123 //       Access: Published
00124 //  Description: Sets up the OpenCVTexture (or the indicated page, if z
00125 //               is specified) to accept its input from the camera
00126 //               with the given index number, or the default camera if
00127 //               the index number is -1 or unspecified.
00128 //
00129 //               If alpha_file_channel is 0, then the camera image
00130 //               becomes a normal RGB texture.  If it is 1, 2, or 3,
00131 //               then the camera image becomes an alpha texture, using
00132 //               the indicated channel of the source.
00133 ////////////////////////////////////////////////////////////////////
00134 bool OpenCVTexture::
00135 from_camera(int camera_index, int z, int alpha_file_channel,
00136             const LoaderOptions &options) {
00137   if (!do_reconsider_z_size(z)) {
00138     return false;
00139   }
00140   nassertr(z >= 0 && z < get_z_size(), false);
00141 
00142   _alpha_file_channel = alpha_file_channel;
00143 
00144   VideoPage &page = modify_page(z);
00145   if (alpha_file_channel == 0) {
00146     // A normal RGB texture.
00147     page._alpha.clear();
00148     if (!page._color.from_camera(camera_index)) {
00149       return false;
00150     }
00151 
00152     if (!do_reconsider_video_properties(page._color, 3, z, options)) {
00153       page._color.clear();
00154       return false;
00155     }
00156   } else {
00157     // An alpha texture.
00158     page._color.clear();
00159     if (!page._alpha.from_camera(camera_index)) {
00160       return false;
00161     }
00162 
00163     if (!do_reconsider_video_properties(page._alpha, 1, z, options)) {
00164       page._alpha.clear();
00165       return false;
00166     }
00167     do_set_format(F_alpha);
00168   }
00169 
00170   set_loaded_from_image();
00171   clear_current_frame();
00172   update_frame(0);
00173   return true;
00174 }
00175 
00176 ////////////////////////////////////////////////////////////////////
00177 //     Function: OpenCVTexture::modify_page
00178 //       Access: Private
00179 //  Description: Returns a reference to the zth VideoPage (level) of
00180 //               the texture.  In the case of a 2-d texture, there is
00181 //               only one page, level 0; but cube maps and 3-d
00182 //               textures have more.
00183 ////////////////////////////////////////////////////////////////////
00184 OpenCVTexture::VideoPage &OpenCVTexture::
00185 modify_page(int z) {
00186   nassertr(z < _z_size, _pages[0]);
00187   while (z >= (int)_pages.size()) {
00188     _pages.push_back(VideoPage());
00189   }
00190   return _pages[z];
00191 }
00192 
00193 ////////////////////////////////////////////////////////////////////
00194 //     Function: OpenCVTexture::do_reconsider_video_properties
00195 //       Access: Private
00196 //  Description: Resets the internal Texture properties when a new
00197 //               video file is loaded.  Returns true if the new image
00198 //               is valid, false otherwise.
00199 ////////////////////////////////////////////////////////////////////
00200 bool OpenCVTexture::
00201 do_reconsider_video_properties(const OpenCVTexture::VideoStream &stream, 
00202                                int num_components, int z, 
00203                                const LoaderOptions &options) {
00204   double frame_rate = 0.0f;
00205   int num_frames = 0;
00206 
00207   if (stream.is_from_file()) {
00208     frame_rate = cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FPS);
00209     num_frames = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_COUNT);
00210     if (vision_cat.is_debug()) {
00211       vision_cat.debug()
00212         << "Loaded " << stream._filename << ", " << num_frames << " frames at "
00213         << frame_rate << " fps\n";
00214     }
00215   } else {
00216     // In this case, we don't have a specific frame rate or number of
00217     // frames.  Let both values remain at 0.
00218     if (vision_cat.is_debug()) {
00219       vision_cat.debug()
00220         << "Loaded camera stream\n";
00221     }
00222   }
00223 
00224   int width = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_WIDTH);
00225   int height = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_HEIGHT);
00226 
00227   int x_size = width;
00228   int y_size = height;
00229 
00230   if (Texture::get_textures_power_2() != ATS_none) {
00231     x_size = up_to_power_2(width);
00232     y_size = up_to_power_2(height);
00233   }
00234 
00235   if (vision_cat.is_debug()) {
00236     vision_cat.debug()
00237       << "Video stream is " << width << " by " << height 
00238       << " pixels; fitting in texture " << x_size << " by "
00239       << y_size << " texels.\n";
00240   }
00241 
00242   if (!do_reconsider_image_properties(x_size, y_size, num_components,
00243                                       T_unsigned_byte, z, options)) {
00244     return false;
00245   }
00246 
00247   if (_loaded_from_image && 
00248       (get_video_width() != width || get_video_height() != height ||
00249        get_num_frames() != num_frames || get_frame_rate() != frame_rate)) {
00250     vision_cat.error()
00251       << "Video properties have changed for texture " << get_name()
00252       << " level " << z << ".\n";
00253     return false;
00254   }
00255 
00256   set_frame_rate(frame_rate);
00257   set_num_frames(num_frames);
00258   set_video_size(width, height);
00259 
00260   // By default, the newly-loaded video stream will immediately start
00261   // looping.
00262   loop(true);
00263 
00264   return true;
00265 }
00266 
00267 ////////////////////////////////////////////////////////////////////
00268 //     Function: OpenCVTexture::make_texture
00269 //       Access: Public, Static
00270 //  Description: A factory function to make a new OpenCVTexture, used
00271 //               to pass to the TexturePool.
00272 ////////////////////////////////////////////////////////////////////
00273 PT(Texture) OpenCVTexture::
00274 make_texture() {
00275   return new OpenCVTexture;
00276 }
00277 
00278 ////////////////////////////////////////////////////////////////////
00279 //     Function: OpenCVTexture::update_frame
00280 //       Access: Protected, Virtual
00281 //  Description: Called once per frame, as needed, to load the new
00282 //               image contents.
00283 ////////////////////////////////////////////////////////////////////
00284 void OpenCVTexture::
00285 update_frame(int frame) {
00286   int max_z = max(_z_size, (int)_pages.size());
00287   for (int z = 0; z < max_z; ++z) {
00288     update_frame(frame, z);
00289   }
00290 }
00291 
00292 ////////////////////////////////////////////////////////////////////
00293 //     Function: OpenCVTexture::update_frame
00294 //       Access: Protected, Virtual
00295 //  Description: This variant of update_frame updates the
00296 //               indicated page only.
00297 ////////////////////////////////////////////////////////////////////
00298 void OpenCVTexture::
00299 update_frame(int frame, int z) {
00300   if (vision_cat.is_spam()) {
00301     vision_cat.spam()
00302       << "Updating OpenCVTexture page " << z << "\n";
00303   }
00304 
00305   VideoPage &page = _pages[z];
00306   if (page._color.is_valid() || page._alpha.is_valid()) {
00307     do_modify_ram_image();
00308     ++_image_modified;
00309   }
00310   ssize_t dest_x_pitch = _num_components * _component_width;
00311   ssize_t dest_y_pitch = _x_size * dest_x_pitch;
00312 
00313   if (page._color.is_valid()) {
00314     nassertv(get_num_components() >= 3 && get_component_width() == 1);
00315 
00316     const unsigned char *r, *g, *b;
00317     ssize_t x_pitch, y_pitch;
00318     if (page._color.get_frame_data(frame, r, g, b, x_pitch, y_pitch)) {
00319       nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
00320       unsigned char *dest = _ram_images[0]._image.p() + do_get_expected_ram_page_size() * z;
00321 
00322       if (_num_components == 3 && x_pitch == 3) {
00323         // The easy case--copy the whole thing in, row by row.
00324         ssize_t copy_bytes = get_video_width() * dest_x_pitch;
00325         nassertv(copy_bytes <= dest_y_pitch && copy_bytes <= abs(y_pitch));
00326 
00327         for (int y = 0; y < get_video_height(); ++y) {
00328           memcpy(dest, r, copy_bytes);
00329           dest += dest_y_pitch;
00330           r += y_pitch;
00331         }
00332 
00333       } else {
00334         // The harder case--interleave in the color channels, pixel by
00335         // pixel, possibly leaving room for alpha.
00336 
00337         for (int y = 0; y < get_video_height(); ++y) {
00338           ssize_t dx = 0;
00339           ssize_t sx = 0;
00340           for (int x = 0; x < get_video_width(); ++x) {
00341             dest[dx] = r[sx];
00342             dest[dx + 1] = g[sx];
00343             dest[dx + 2] = b[sx];
00344             dx += dest_x_pitch;
00345             sx += x_pitch;
00346           }
00347           dest += dest_y_pitch;
00348           r += y_pitch;
00349           g += y_pitch;
00350           b += y_pitch;
00351         }
00352       }
00353     }
00354   }
00355   if (page._alpha.is_valid()) {
00356     nassertv(get_component_width() == 1);
00357 
00358     const unsigned char *source[3];
00359     ssize_t x_pitch, y_pitch;
00360     if (page._alpha.get_frame_data(frame, source[0], source[1], source[2],
00361                                    x_pitch, y_pitch)) {
00362       nassertv(get_video_width() <= _x_size && get_video_height() <= _y_size);
00363       unsigned char *dest = _ram_images[0]._image.p() + do_get_expected_ram_page_size() * z;
00364 
00365       // Interleave the alpha in with the color, pixel by pixel.
00366       // Even though the alpha will probably be a grayscale video,
00367       // the OpenCV library presents it as RGB.
00368       const unsigned char *sch = source[0];
00369       if (_alpha_file_channel >= 1 && _alpha_file_channel <= 3) {
00370         sch = source[_alpha_file_channel - 1];
00371       }
00372       
00373       for (int y = 0; y < get_video_height(); ++y) {
00374         // Start dx at _num_components - 1, which writes to the last
00375         // channel, i.e. the alpha channel.
00376         ssize_t dx = (_num_components - 1) * _component_width; 
00377         ssize_t sx = 0;
00378         for (int x = 0; x < get_video_width(); ++x) {
00379           dest[dx] = sch[sx];
00380           dx += dest_x_pitch;
00381           sx += x_pitch;
00382         }
00383         dest += dest_y_pitch;
00384         sch += y_pitch;
00385       }
00386     }
00387   }
00388 }
00389 
00390 ////////////////////////////////////////////////////////////////////
00391 //     Function: OpenCVTexture::do_read_one
00392 //       Access: Protected, Virtual
00393 //  Description: Combines a color and alpha video image from the two
00394 //               indicated filenames.  Both must be the same kind of
00395 //               video with similar properties.
00396 ////////////////////////////////////////////////////////////////////
00397 bool OpenCVTexture::
00398 do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
00399             int z, int n, int primary_file_num_channels, int alpha_file_channel,
00400             const LoaderOptions &options,
00401             bool header_only, BamCacheRecord *record) {
00402   if (record != (BamCacheRecord *)NULL) {
00403     record->add_dependent_file(fullpath);
00404   }
00405 
00406   nassertr(n == 0, false);
00407   nassertr(z >= 0 && z < _z_size, false);
00408 
00409   VideoPage &page = modify_page(z);
00410   if (!page._color.read(fullpath)) {
00411     vision_cat.error()
00412       << "OpenCV couldn't read " << fullpath << " as video.\n";
00413     return false;
00414   }
00415   if (!alpha_fullpath.empty()) {
00416     if (!page._alpha.read(alpha_fullpath)) {
00417       vision_cat.error()
00418         << "OpenCV couldn't read " << alpha_fullpath << " as video.\n";
00419       page._color.clear();
00420       return false;
00421     }
00422   }
00423 
00424   if (z == 0) {
00425     if (!has_name()) {
00426       set_name(fullpath.get_basename_wo_extension());
00427     }
00428     // Don't use has_filename() here, it will cause a deadlock
00429     if (_filename.empty()) {
00430       _filename = fullpath;
00431       _alpha_filename = alpha_fullpath;
00432     }
00433 
00434     _fullpath = fullpath;
00435     _alpha_fullpath = alpha_fullpath;
00436   }
00437 
00438   _primary_file_num_channels = 3;
00439   _alpha_file_channel = 0;
00440 
00441   if (alpha_fullpath.empty()) {
00442     // Only one RGB movie.
00443     if (!do_reconsider_video_properties(page._color, 3, z, options)) {
00444       page._color.clear();
00445       return false;
00446     }
00447 
00448   } else {
00449     // An RGB movie combined with an alpha movie.
00450     _alpha_file_channel = alpha_file_channel;
00451 
00452     if (!do_reconsider_video_properties(page._color, 4, z, options)) {
00453       page._color.clear();
00454       page._alpha.clear();
00455       return false;
00456     }
00457     
00458     if (!do_reconsider_video_properties(page._alpha, 4, z, options)) {
00459       page._color.clear();
00460       page._alpha.clear();
00461       return false;
00462     }
00463   }
00464 
00465   set_loaded_from_image();
00466   clear_current_frame();
00467   update_frame(0);
00468   return true;
00469 }
00470 
00471 ////////////////////////////////////////////////////////////////////
00472 //     Function: OpenCVTexture::do_load_one
00473 //       Access: Protected, Virtual
00474 //  Description: Resets the texture (or the particular level of the
00475 //               texture) to the indicated static image.
00476 ////////////////////////////////////////////////////////////////////
00477 bool OpenCVTexture::
00478 do_load_one(const PNMImage &pnmimage, const string &name,
00479             int z, int n, const LoaderOptions &options) {
00480   if (z <= (int)_pages.size()) {
00481     VideoPage &page = modify_page(z);
00482     page._color.clear();
00483     page._alpha.clear();
00484   }
00485 
00486   return Texture::do_load_one(pnmimage, name, z, n, options);
00487 }
00488 
00489 ////////////////////////////////////////////////////////////////////
00490 //     Function: OpenCVTexture::register_with_read_factory
00491 //       Access: Public, Static
00492 //  Description: Factory method to generate a Texture object
00493 ////////////////////////////////////////////////////////////////////
00494 void OpenCVTexture::
00495 register_with_read_factory() {
00496   // Since Texture is such a funny object that is reloaded from the
00497   // TexturePool each time, instead of actually being read fully from
00498   // the bam file, and since the VideoTexture and OpenCVTexture
00499   // classes don't really add any useful data to the bam record, we
00500   // don't need to define make_from_bam(), fillin(), or
00501   // write_datagram() in this class--we just inherit the same
00502   // functions from Texture.
00503 
00504   // We do, however, have to register this class with the BamReader,
00505   // to avoid warnings about creating the wrong kind of object from
00506   // the bam file.
00507   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00508 }
00509 
00510 ////////////////////////////////////////////////////////////////////
00511 //     Function: OpenCVTexture::VideoStream::Constructor
00512 //       Access: Public
00513 //  Description: 
00514 ////////////////////////////////////////////////////////////////////
00515 OpenCVTexture::VideoStream::
00516 VideoStream() :
00517   _capture(NULL),
00518   _camera_index(-1),
00519   _next_frame(0)
00520 {
00521 }
00522 
00523 ////////////////////////////////////////////////////////////////////
00524 //     Function: OpenCVTexture::VideoStream::Copy Constructor
00525 //       Access: Public
00526 //  Description: 
00527 ////////////////////////////////////////////////////////////////////
00528 OpenCVTexture::VideoStream::
00529 VideoStream(const OpenCVTexture::VideoStream &copy) :
00530   _capture(NULL),
00531   _camera_index(-1)
00532 {
00533   // Rather than copying the _capture pointer, we must open a new
00534   // stream that references the same file.
00535   if (copy.is_valid()) {
00536     if (copy.is_from_file()) {
00537       read(copy._filename);
00538     } else {
00539       from_camera(copy._camera_index);
00540     }
00541   }
00542 }
00543 
00544 ////////////////////////////////////////////////////////////////////
00545 //     Function: OpenCVTexture::VideoStream::Copy Constructor
00546 //       Access: Public
00547 //  Description: 
00548 ////////////////////////////////////////////////////////////////////
00549 OpenCVTexture::VideoStream::
00550 ~VideoStream() {
00551   clear();
00552 }
00553 
00554 ////////////////////////////////////////////////////////////////////
00555 //     Function: OpenCVTexture::VideoStream::get_frame_data
00556 //       Access: Public
00557 //  Description: Gets the data needed to traverse through the
00558 //               decompressed buffer for the indicated frame number.
00559 //               It is most efficient to call this in increasing order
00560 //               of frame number.  Returns true on success, false on
00561 //               failure.
00562 //
00563 //               In the case of a success indication (true return
00564 //               value), the three pointers r, g, b are loaded with
00565 //               the addresses of the three components of the
00566 //               bottom-left pixel of the image.  (They will be
00567 //               adjacent in memory in the case of an interleaved
00568 //               image, and separated in the case of a
00569 //               separate-channel image.)  The x_pitch value is filled
00570 //               with the amount to add to each pointer to advance to
00571 //               the pixel to the right; and the y_pitch value is
00572 //               filled with the amount to add to each pointer to
00573 //               advance to the pixel above.  Note that these values
00574 //               may be negative (particularly in the case of a
00575 //               top-down image).
00576 ////////////////////////////////////////////////////////////////////
00577 bool OpenCVTexture::VideoStream::
00578 get_frame_data(int frame,
00579                const unsigned char *&r,
00580                const unsigned char *&g,
00581                const unsigned char *&b,
00582                ssize_t &x_pitch, ssize_t &y_pitch) {
00583   nassertr(is_valid(), false);
00584 
00585   if (is_from_file() && _next_frame != frame) {
00586     cvSetCaptureProperty(_capture, CV_CAP_PROP_POS_FRAMES, frame);
00587   }
00588 
00589   _next_frame = frame + 1;
00590   IplImage *image = cvQueryFrame(_capture);
00591   if (image == NULL) {
00592     return false;
00593   }
00594 
00595   r = (const unsigned char *)image->imageData;
00596   g = r + 1;
00597   b = g + 1;
00598   x_pitch = 3;
00599   y_pitch = image->widthStep;
00600 
00601   if (image->dataOrder == 1) {
00602     // Separate channel images.  That means a block of r, followed by
00603     // a block of g, followed by a block of b.
00604     x_pitch = 1;
00605     g = r + image->height * y_pitch;
00606     b = g + image->height * y_pitch;
00607   }
00608 
00609   if (image->origin == 0) {
00610     // The image data starts with the top row and ends with the bottom
00611     // row--the opposite of Texture::_ram_data's storage convention.
00612     // Therefore, we must increment the initial pointers to the last
00613     // row, and count backwards.
00614     r += (image->height - 1) * y_pitch;
00615     g += (image->height - 1) * y_pitch;
00616     b += (image->height - 1) * y_pitch;
00617     y_pitch = -y_pitch;
00618   }
00619 
00620   return true;
00621 }
00622 
00623 ////////////////////////////////////////////////////////////////////
00624 //     Function: OpenCVTexture::VideoStream::read
00625 //       Access: Public
00626 //  Description: Sets up the stream to read the indicated file.
00627 //               Returns true on success, false on failure.
00628 ////////////////////////////////////////////////////////////////////
00629 bool OpenCVTexture::VideoStream::
00630 read(const Filename &filename) {
00631   clear();
00632 
00633   string os_specific = filename.to_os_specific();
00634   _capture = cvCaptureFromFile(os_specific.c_str());
00635   if (_capture == NULL) {
00636     return false;
00637   }
00638   _filename = filename;
00639   return true;
00640 }
00641 
00642 ////////////////////////////////////////////////////////////////////
00643 //     Function: OpenCVTexture::VideoStream::from_camera
00644 //       Access: Public
00645 //  Description: Sets up the stream to display the indicated camera.
00646 //               Returns true on success, false on failure.
00647 ////////////////////////////////////////////////////////////////////
00648 bool OpenCVTexture::VideoStream::
00649 from_camera(int camera_index) {
00650   clear();
00651 
00652   _capture = cvCaptureFromCAM(camera_index);
00653   if (_capture == NULL) {
00654     return false;
00655   }
00656   _camera_index = camera_index;
00657   return true;
00658 }
00659 
00660 ////////////////////////////////////////////////////////////////////
00661 //     Function: OpenCVTexture::VideoStream::clear
00662 //       Access: Public
00663 //  Description: Stops the video playback and frees the associated
00664 //               resources.
00665 ////////////////////////////////////////////////////////////////////
00666 void OpenCVTexture::VideoStream::
00667 clear() {
00668   if (_capture != NULL) {
00669     cvReleaseCapture(&_capture);
00670     _capture = NULL;
00671   }
00672   _filename = Filename();
00673   _camera_index = -1;
00674   _next_frame = 0;
00675 }
00676 
00677 #endif  // HAVE_OPENCV
00678 
 All Classes Functions Variables Enumerations