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