OpenVideo Documentation

   Main Page       Modules       Class Hierarchy       Alphabetical List       Compound List       File List       Compound Members       Related Pages   

V4L2Src.cxx

Go to the documentation of this file.
00001 /* ========================================================================
00002  * Copyright (C) 2005  Graz University of Technology
00003  *
00004  * This framework is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This framework is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this framework; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  *
00018  * For further information please contact Denis Kalkofen under
00019  * <kalkofen@icg.tu-graz.ac.at> or write to Denis Kalkofen,
00020  * Graz University of Technology, Inffeldgasse 16a, A8010 Graz,
00021  * Austria.
00022  * ========================================================================
00023  * PROJECT: OpenVideo
00024  * ======================================================================== */
00034 #ifdef ENABLE_V4L2SRC
00035 
00036 #include <openvideo/nodes/V4L2Src.h>
00037 #include <openvideo/Manager.h>
00038 #include <openvideo/State.h>
00039 
00040 #include <cstdio>
00041 #include <cstdlib>
00042 #include <cassert>
00043 
00044 #include <fstream>
00045 #include <iostream>
00046 
00047 #include <fcntl.h>              /* low-level i/o */
00048 #include <unistd.h>
00049 #include <errno.h>
00050 #include <sys/stat.h>
00051 #include <sys/types.h>
00052 #include <sys/time.h>
00053 #include <sys/mman.h>
00054 #include <sys/ioctl.h>
00055 
00056 #include <asm/types.h>          /* for videodev2.h */
00057 #include <linux/videodev2.h>
00058 
00059 // only required for setting framerate manually
00060 #include <linux/videodev.h>
00061 
00062 #define CLEAR(x) memset (&(x), 0, sizeof (x))
00063 
00064 namespace openvideo {
00065 
00066     // V4L2SrcBuffer gives V4L2Src full access to openvideo::Buffer
00067     class V4L2SrcBuffer : public Buffer
00068     {
00069     friend class V4L2Src;
00070     public:
00071     V4L2SrcBuffer(unsigned char* pixbuffer)
00072     {
00073             buffer = pixbuffer;
00074     }
00075         
00076     ~V4L2SrcBuffer()
00077     {
00078             delete buffer;
00079             buffer = NULL;
00080     }
00081 
00082     void incUpdateCounter()  {  updateCtr++;  }
00083         
00084     };
00085 
00086 
00087     //V4L2SrcState gives V4L2Src full access to openvideo::State
00088     class V4L2SrcState : public State
00089     {
00090     public:
00091     BufferVector& getBuffers()  {  return buffers;  }
00092         void setCurrentBuffer(Buffer* buf)  {  currentBuffer = buf;  }
00093     };
00094     
00095 #define V4L2_State(_STATE)    reinterpret_cast<V4L2SrcState*>(_STATE)
00096     
00097     
00098     // Initialize variable to default values.
00099     V4L2Src::V4L2Src() : videoWidth(640), videoHeight(480), fps(10),
00100                          pixelFormat(FORMAT_R8G8B8X8), videoFd(-1),
00101                          ioMode(IO_METHOD_MMAP), buffers(NULL), nBuffers(0), 
00102                          initialized(false)
00103     {
00104         strcpy(videoDevice, "/dev/video0");
00105 
00106         // allocate new state
00107         state = new V4L2SrcState;
00108     }
00109     
00110     V4L2Src::~V4L2Src()
00111     {
00112         state->unlockAllBuffers();
00113         delete state;
00114     }
00115 
00116     void 
00117     V4L2Src::init() {
00118 
00119         state->clear();
00120 
00121     Manager::getInstance()->getLogger()->logEx("Resolution = %d %d\n", videoWidth, videoHeight);
00122 
00123 
00124         state->width=videoWidth;
00125         state->height=videoHeight;
00126         state->format=pixelFormat;
00127 
00128     // make a double buffered state
00129     Manager::getInstance()->getLogger()->logEx("V4L2Src: Using double buffering\n");        
00130     for(int i=0; i<2; i++)
00131     {
00132             unsigned char *pixels = (unsigned char*)malloc(videoWidth*videoHeight*sizeof(unsigned int));
00133             // clear buffer
00134             memset(pixels, 0, videoWidth*videoHeight*sizeof(unsigned int));
00135             
00136             reinterpret_cast<V4L2SrcState*>(state)->getBuffers().push_back(new V4L2SrcBuffer(pixels));
00137     }
00138         
00139         // initialization (must be done after setting all parameters)
00140     Manager::getInstance()->getLogger()->log("OpenVideo: starting driver initialization ... ");
00141         
00142         if (openDevice())
00143             initialized = initDevice();
00144         
00145         if (!initialized) return;
00146 
00147         // setting the framerate
00148         setFrameRate(fps);
00149     Manager::getInstance()->getLogger()->log("done.\n");
00150     }
00151     
00152     void 
00153     V4L2Src::initPixelFormats() {
00154         pixelFormats.push_back(PIXEL_FORMAT(FORMAT_R8G8B8X8));
00155     }
00156 
00157     void
00158     V4L2Src::start()
00159     {
00160         using namespace std;
00161         
00162         unsigned int i;
00163         enum v4l2_buf_type type;
00164 
00165     switch (ioMode) {
00166             case IO_METHOD_READ:
00167                 Manager::getInstance()->getLogger()->log("INFO: using standard read method.\n");
00168         /* Nothing to do. */
00169         break;
00170                 
00171             case IO_METHOD_MMAP:
00172                 Manager::getInstance()->getLogger()->log("INFO: using memory mapped file method.\n");
00173         for (i = 0; i < nBuffers; ++i) {
00174                     struct v4l2_buffer buf;
00175 
00176                     CLEAR (buf);
00177 
00178                     buf.type            = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00179                     buf.memory          = V4L2_MEMORY_MMAP;
00180                     buf.index           = i;
00181 
00182                     if (xioctl (videoFd, VIDIOC_QBUF, &buf) == -1)
00183                         assert(0);
00184         }
00185         
00186         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00187                 
00188         if (xioctl (videoFd, VIDIOC_STREAMON, &type) == -1)
00189                     assert(0);
00190 
00191         break;
00192 
00193             case IO_METHOD_USERPTR:
00194                 Manager::getInstance()->getLogger()->log("INFO: using user pointer method.\n");
00195         for (i = 0; i < nBuffers; ++i) {
00196                     struct v4l2_buffer buf;
00197 
00198                     CLEAR (buf);
00199 
00200                     buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00201                     buf.memory      = V4L2_MEMORY_USERPTR;
00202                     buf.m.userptr   = (unsigned long) buffers[i].start;
00203                     buf.length      = buffers[i].length;
00204 
00205                     if (xioctl (videoFd, VIDIOC_QBUF, &buf) == -1)
00206                         assert(0);
00207         }
00208                 
00209         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00210 
00211         if (xioctl (videoFd, VIDIOC_STREAMON, &type) == -1)
00212                     assert(0);
00213                 
00214         break;
00215     }
00216     }
00217 
00218     void
00219     V4L2Src::process()
00220     {
00221         if (!initialized) return;
00222 
00223         using namespace std; 
00224 
00225         if (videoFd < 0) {
00226             Manager::getInstance()->getLogger()->log("ERROR: no video devices available.\n");
00227             return;
00228         }
00229 
00230         struct v4l2_buffer buf;
00231     unsigned int i;
00232 
00233     switch (ioMode) 
00234         {
00235             case IO_METHOD_READ:
00236             if (read (videoFd, buffers[0].start, buffers[0].length) == -1)
00237                 {
00238                     switch (errno) 
00239                     {
00240                     case EAGAIN:
00241                             return;
00242                             
00243             case EIO:
00244                             /* Could ignore EIO, see spec. */
00245                             
00246                             /* fall through */
00247                             
00248             default:
00249                             assert(0);
00250                     }
00251         }
00252                 
00253             processImage ((char*)buffers[0].start);
00254                 
00255         break;
00256                 
00257             case IO_METHOD_MMAP:
00258         CLEAR (buf);
00259                 
00260                 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00261                 buf.memory = V4L2_MEMORY_MMAP;
00262                 
00263             if (xioctl (videoFd, VIDIOC_DQBUF, &buf) == -1) {
00264                     switch (errno) 
00265                     {
00266                     case EAGAIN:
00267                             return;
00268                             
00269             case EIO:
00270                             /* Could ignore EIO, see spec. */
00271                             
00272                             /* fall through */
00273                             
00274             default:
00275                             assert(0);
00276                     }
00277         }
00278                 
00279                 assert (buf.index < nBuffers);
00280                 
00281             processImage ((char*)buffers[buf.index].start);
00282 
00283         if (xioctl (videoFd, VIDIOC_QBUF, &buf) == -1)
00284                     assert(0);
00285 
00286         break;
00287                 
00288             case IO_METHOD_USERPTR:
00289         CLEAR (buf);
00290 
00291             buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00292             buf.memory = V4L2_MEMORY_USERPTR;
00293                 
00294         if (xioctl (videoFd, VIDIOC_DQBUF, &buf) == -1) 
00295                 {
00296                     switch (errno) 
00297                     {
00298             case EAGAIN:
00299                             return;
00300                             
00301             case EIO:
00302                             /* Could ignore EIO, see spec. */
00303                             
00304                             /* fall through */
00305                             
00306             default:
00307                             assert(0);
00308                     }
00309         }
00310                 
00311         for (i = 0; i < nBuffers; ++i)
00312                     if (buf.m.userptr == (unsigned long) buffers[i].start
00313                         && buf.length == buffers[i].length)
00314                         break;
00315                 
00316         assert (i < nBuffers);
00317 
00318             processImage ((void *) buf.m.userptr);
00319                 
00320         if (xioctl (videoFd, VIDIOC_QBUF, &buf) == -1)
00321                     assert(0);
00322                 
00323         break;
00324     }
00325 
00326     }
00327 
00328     void
00329     V4L2Src::processImage(const void* p) 
00330     {
00331     V4L2SrcBuffer* buffer = reinterpret_cast<V4L2SrcBuffer*>(state->findFreeBuffer());
00332 
00333     if(!buffer)
00334     {
00335             Manager::getInstance()->getLogger()->log("OpenVideo::V4L2Src all buffers locked, can not read a new camera image!\n");
00336             return;
00337     }
00338     unsigned char* img = const_cast<unsigned char*>(buffer->getPixels());
00339 
00340         // convert from YUV420 to RGBA32
00341         converter.convertToRGB32((unsigned char*)p, videoWidth, videoHeight, reinterpret_cast<unsigned int*>(img), false);
00342         V4L2_State(state)->setCurrentBuffer(buffer);
00343         
00344     buffer->incUpdateCounter();
00345     }
00346 
00347     void
00348     V4L2Src::postProcess()
00349     {
00350     }
00351 
00352     bool
00353     V4L2Src::setParameter(std::string key, std::string value)
00354     {
00355         using namespace std;
00356     Manager::getInstance()->getLogger()->logEx("V4L2Src::setParameter: %s %s\n", key.c_str(), value.c_str());
00357         if(Node::setParameter(key,value))
00358             return true;
00359 
00360 
00361         if(key=="width")
00362         {
00363             this->videoWidth=atoi(value.c_str());
00364             return true;
00365         }
00366         else if(key=="height")
00367         {
00368             this->videoHeight=atoi(value.c_str());
00369             return true;
00370         }
00371         else if (key=="device")
00372         {
00373             strcpy(this->videoDevice, value.c_str());
00374             return true;
00375         }
00376         else if (key=="fps")
00377         {
00378             this->fps=atoi(value.c_str());
00379             return true;
00380         }
00381         else if (key=="format")
00382         {
00383             PIXEL_FORMAT pf = PixelFormat::StringToFormat(value);
00384 
00385             switch(pf) {
00386                 case (FORMAT_R8G8B8X8):
00387                     pixelFormat = pf;
00388                     break;
00389                 default:
00390                     cout << "PixelFormat " << value << " is not supported. "
00391                          << "Using default value " << PixelFormat::FormatToString(pixelFormat) << endl;
00392             }
00393       
00394             return true;
00395         }
00396         else
00397         {
00398             cout << "No key: " << key << endl;
00399         }
00400         return false;
00401     }
00402 
00403 
00404     bool
00405     V4L2Src::openDevice() 
00406     {
00407         using namespace std;
00408         
00409         struct stat st; 
00410         
00411         if (videoFd != -1) 
00412         {
00413             closeDevice();
00414         }
00415         
00416         if (stat(videoDevice, &st) == -1) 
00417         {
00418             cerr << "ERROR: cannot identify given device " << videoDevice << endl;
00419             return false;
00420         }
00421 
00422         if (!S_ISCHR (st.st_mode)) {
00423             cerr << "ERROR: given device is not a real device" << endl;
00424             return false;
00425         }
00426         
00427         videoFd = open(videoDevice, O_RDWR /* required */ | O_NONBLOCK, 0);
00428         
00429         if (videoFd == -1) {
00430             cerr << "ERROR: cannot open device" << endl;
00431             return false;
00432         }
00433         
00434     }
00435 
00436     bool
00437     V4L2Src::initDevice() 
00438     {
00439         using namespace std; 
00440 
00441         struct v4l2_capability cap;
00442         struct v4l2_cropcap cropcap;
00443         struct v4l2_crop crop;
00444         struct v4l2_format fmt;
00445     unsigned int min;
00446         
00447         if (xioctl (videoFd, VIDIOC_QUERYCAP, &cap) == -1) {
00448             if (errno == EINVAL) {
00449                 cerr << "ERROR: " << videoDevice << " is no V4L2 device" << endl;
00450                 return false;
00451             }
00452             return false;
00453         }
00454         
00455         if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
00456             cerr << "ERROR: " << videoDevice << " is no video capture device" << endl;
00457             return false;
00458         }
00459         
00460     switch (ioMode) {
00461             case IO_METHOD_READ:
00462         if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
00463                     cerr << "ERROR: " << videoDevice << " does not support read i/o" << endl;
00464                     return false;
00465         }
00466                 break;
00467                 
00468             case IO_METHOD_MMAP:
00469             case IO_METHOD_USERPTR:
00470         if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
00471                     cerr << "ERROR: " << videoDevice << " does not support streaming i/o" << endl;
00472                     return false;
00473         }
00474         break;
00475     };
00476 
00477 
00478         /* Select video input, video standard and tune here. */
00479 
00480 
00481     CLEAR (cropcap);
00482 
00483         cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00484         
00485         if (xioctl (videoFd, VIDIOC_CROPCAP, &cropcap) == 0) {
00486             crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00487             crop.c = cropcap.defrect; /* reset to default */
00488             
00489             if (xioctl (videoFd, VIDIOC_S_CROP, &crop) == -1) {
00490                 switch (errno) {
00491                     case EINVAL:
00492                         /* Cropping not supported. */
00493                         break;
00494                     default:
00495                         /* Errors ignored. */
00496                         break;
00497                 }
00498             }
00499         } else {    
00500             /* Errors ignored. */
00501         }
00502 
00503         
00504         CLEAR (fmt);
00505 
00506         fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00507         fmt.fmt.pix.width       = videoWidth; 
00508         fmt.fmt.pix.height      = videoHeight;
00509         fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
00510         fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
00511 
00512         if (xioctl (videoFd, VIDIOC_S_FMT, &fmt) == -1)
00513             return false;
00514         
00515         /* Note VIDIOC_S_FMT may change width and height. */
00516 
00517     /* Buggy driver paranoia. */
00518     min = fmt.fmt.pix.width * 2;
00519     if (fmt.fmt.pix.bytesperline < min)
00520             fmt.fmt.pix.bytesperline = min;
00521     min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
00522     if (fmt.fmt.pix.sizeimage < min)
00523             fmt.fmt.pix.sizeimage = min;
00524         
00525     switch (ioMode) {
00526             case IO_METHOD_READ:
00527         return initIORead (fmt.fmt.pix.sizeimage);
00528         break;
00529                 
00530             case IO_METHOD_MMAP:
00531         return initIOMMap ();
00532         break;
00533                 
00534             case IO_METHOD_USERPTR:
00535         return initIOUserp (fmt.fmt.pix.sizeimage);
00536         break;
00537     };
00538     }
00539 
00540     bool 
00541     V4L2Src::initIORead(unsigned int bufferSize)
00542     {
00543         using namespace std; 
00544         buffers = (buffer*)calloc (1, sizeof (*buffers));
00545         
00546         if (!buffers) {
00547             cerr << "ERROR: Out of memory" << endl;
00548             return false;
00549         }
00550 
00551     buffers[0].length = bufferSize;
00552     buffers[0].start = malloc(bufferSize);
00553         
00554     if (!buffers[0].start) {
00555             cerr << "ERROR: Out of memory" << endl;
00556             return false;
00557     }
00558     }
00559 
00560     bool V4L2Src::initIOMMap()
00561     {
00562         using namespace std; 
00563     struct v4l2_requestbuffers req;
00564 
00565         CLEAR (req);
00566         
00567         req.count               = 4;
00568         req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00569         req.memory              = V4L2_MEMORY_MMAP;
00570 
00571     if (xioctl (videoFd, VIDIOC_REQBUFS, &req) == -1) 
00572         {
00573             if (EINVAL == errno) 
00574                 cerr << "ERROR: " << videoDevice << " does not support memory mapping" << endl;
00575             return false;
00576         }
00577 
00578         if (req.count < 2) 
00579         {
00580             cerr << "ERROR: Insufficient buffer memory" << endl;
00581             return false;
00582         }
00583 
00584         buffers = (buffer*)calloc (req.count, sizeof (*buffers));
00585 
00586         if (!buffers) {
00587             cerr << "ERROR: Out of memory" << endl;
00588             return false;
00589         }
00590         
00591         for (nBuffers = 0; nBuffers < req.count; ++nBuffers) {
00592             struct v4l2_buffer buf;
00593             
00594             CLEAR (buf);
00595             
00596             buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00597             buf.memory      = V4L2_MEMORY_MMAP;
00598             buf.index       = nBuffers;
00599             
00600             if (xioctl (videoFd, VIDIOC_QUERYBUF, &buf) == -1)
00601                 assert(0);
00602 
00603             buffers[nBuffers].length = buf.length;
00604             buffers[nBuffers].start =
00605                 mmap (NULL /* start anywhere */,
00606                       buf.length,
00607                       PROT_READ | PROT_WRITE /* required */,
00608                       MAP_SHARED /* recommended */,
00609                       videoFd, buf.m.offset);
00610             
00611             if (MAP_FAILED == buffers[nBuffers].start)
00612                 assert(0);
00613         }
00614     }
00615     
00616     bool 
00617     V4L2Src::initIOUserp(unsigned int bufferSize)
00618     {
00619         using namespace std; 
00620     struct v4l2_requestbuffers req;
00621         
00622         CLEAR (req);
00623         
00624         req.count               = 4;
00625         req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00626         req.memory              = V4L2_MEMORY_USERPTR;
00627 
00628         if (xioctl (videoFd, VIDIOC_REQBUFS, &req) == -1) {
00629             if (EINVAL == errno) 
00630                 cerr << "ERROR: " << videoDevice << " does not support user pointer i/o" << endl;
00631             return false;
00632         }
00633 
00634         buffers = (buffer*)calloc (4, sizeof (*buffers));
00635 
00636         if (!buffers) {
00637             cerr << "ERROR: Out of memory" << endl;
00638             return false;
00639         }
00640         
00641         for (nBuffers = 0; nBuffers < 4; ++nBuffers) {
00642             buffers[nBuffers].length = bufferSize;
00643             buffers[nBuffers].start = malloc (bufferSize);
00644 
00645             if (!buffers[nBuffers].start) {
00646                 cerr << "ERROR: Out of memory" << endl;
00647                 return false;
00648             }
00649         }
00650     }
00651     
00652     void
00653     V4L2Src::closeDevice() 
00654     {
00655         using namespace std; 
00656         unsigned int i;
00657         
00658     switch (ioMode) {
00659             case IO_METHOD_READ:
00660         free(buffers[0].start);
00661         break;
00662                 
00663             case IO_METHOD_MMAP:
00664         for (i = 0; i < nBuffers; ++i)
00665                     if (-1 == munmap (buffers[i].start, buffers[i].length))
00666                         assert(0);
00667         break;
00668                 
00669             case IO_METHOD_USERPTR:
00670         for (i = 0; i < nBuffers; ++i)
00671                     free (buffers[i].start);
00672         break;
00673     }
00674         
00675     free(buffers);
00676         
00677         if (close (videoFd) == -1)
00678             cerr << "ERROR: Error while closing the device" << endl;
00679         
00680         videoFd = -1;
00681 
00682 //         cerr << "Device closed successfully." << endl;
00683     }
00684 
00685     void
00686     V4L2Src::stop() 
00687     {
00688         initialized = false;
00689 
00690         enum v4l2_buf_type type;
00691 
00692     switch (ioMode) {
00693             case IO_METHOD_READ:
00694         /* Nothing to do. */
00695         break;
00696                 
00697             case IO_METHOD_MMAP:
00698             case IO_METHOD_USERPTR:
00699         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00700 
00701         if (xioctl (videoFd, VIDIOC_STREAMOFF, &type) == -1)
00702                     assert (0);
00703                 break;
00704     }
00705 
00706         closeDevice();
00707     }
00708 
00709     int
00710     V4L2Src::xioctl(int fd, int request, void *arg)
00711     {
00712         int r;
00713         
00714         do r = ioctl (fd, request, arg);
00715         while (r == -1 && errno == EINTR);
00716         
00717         return r;
00718     }
00719 
00720     void
00721     V4L2Src::setFrameRate(int fps) 
00722     {
00723     struct video_window vwin;
00724         
00725     /* get resolution/framerate */
00726     if (ioctl(videoFd, VIDIOCGWIN, &vwin) == -1)
00727             return;
00728         
00729     if (vwin.flags & V4L2_FPS_FRMASK)
00730     {
00731             /* set new framerate */
00732             vwin.flags &= ~V4L2_FPS_FRMASK;
00733             vwin.flags |= (fps << V4L2_FPS_SHIFT);
00734             
00735             if (ioctl(videoFd, VIDIOCSWIN, &vwin) == -1)
00736                 return;
00737     }
00738     else
00739     {
00740             fprintf(stderr, "This device doesn't support setting the framerate.\n");
00741             exit(1);
00742     }
00743     }
00744     
00745 
00746 } // namespace
00747 
00748 #endif // ENABLE_V4L2SRC
00749 
00750 //========================================================================
00751 // End of $FILENAME$
00752 //========================================================================
00753 // Local Variables:
00754 // mode: c++
00755 // c-basic-offset: 4
00756 // eval: (c-set-offset 'substatement-open 0)
00757 // eval: (c-set-offset 'case-label '+)
00758 // eval: (c-set-offset 'statement 'c-lineup-runin-statements)
00759 // eval: (setq indent-tabs-mode nil)
00760 // End:
00761 //========================================================================
 This page was generated at Wed May 31 13:04:16 2006 for OpenVideo by Doxygen.
 If you have any comments, please send a message to schmalstieg@icg.tu-graz.ac.at.
www.studierstube.org