Panda3D
|
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 ©) : 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 ©) : 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