/* Copyright (C) 2005 by Jasem Mutlaq Some code based on qastrocam This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include "ccvt.h" #include "v4l1_base.h" #include "../eventloop.h" #include "../indidevapi.h" #define ERRMSGSIZ 1024 using namespace std; V4L1_Base::V4L1_Base() { frameRate=10; fd=-1; //usingTimer = false; //frameUpdate = true; //selectCallBackID = -1; //timerCallBackID = -1; YBuf = NULL; UBuf = NULL; VBuf = NULL; colorBuffer= NULL; buffer_start=NULL; } V4L1_Base::~V4L1_Base() { delete (YBuf); delete (UBuf); delete (VBuf); delete (colorBuffer); } int V4L1_Base::connectCam(const char * devpath, char *errmsg) { options= (haveBrightness|haveContrast|haveHue|haveColor|haveWhiteness); buffer_start=NULL; frameRate=10; fd=-1; //usingTimer = false; //frameUpdate = true; //selectCallBackID = -1; //timerCallBackID = -1; cerr << "In connect Cam with device " << devpath << endl; if (-1 == (fd=open(devpath, O_RDONLY | O_NONBLOCK, 0))) { strncpy(errmsg, strerror(errno), ERRMSGSIZ); cerr << strerror(errno); return -1; } cerr << "Device opened" << endl; if (fd != -1) { if (-1 == ioctl(fd,VIDIOCGCAP,&capability)) { cerr << "Error: ioctl (VIDIOCGCAP)" << endl; strncpy(errmsg, "ioctl (VIDIOCGCAP)", ERRMSGSIZ); return -1; } if (-1 == ioctl (fd, VIDIOCGWIN, &window)) { cerr << "Error ioctl (VIDIOCGWIN)" << endl; strncpy(errmsg, "ioctl (VIDIOCGWIN)", ERRMSGSIZ); return -1; } if (-1 == ioctl (fd, VIDIOCGPICT, &picture_format)) { cerr << "Error: ioctl (VIDIOCGPICT)" << endl; strncpy(errmsg, "ioctl (VIDIOCGPICT)", ERRMSGSIZ); return -1; } init(0); } cerr << "initial size w:" << window.width << " -- h: " << window.height << endl; /*if (options & ioUseSelect) { selectCallBackID = addCallback(fd, V4L1_Base::staticUpdateFrame, this); cerr << "Using select to wait new frames." << endl; } else { usingTimer = true; timerCallBackID = addTimer(1000/frameRate, V4L1_Base::staticCallFrame, this); cerr << "Using timer to wait new frames.\n"; } */ mmapInit(); //mmapCapture(); cerr << "All successful, returning\n"; return fd; } void V4L1_Base::disconnectCam() { delete YBuf; delete UBuf; delete VBuf; YBuf = UBuf = VBuf = NULL; if (selectCallBackID != -1) rmCallback(selectCallBackID); //if (usingTimer && timerCallBackID != -1) //rmTimer(timerCallBackID); if (munmap (buffer_start, mmap_buffer.size) < 0) fprintf(stderr, "munmap: %s\n", strerror(errno)); if (close(fd) < 0) fprintf(stderr, "close(fd): %s\n", strerror(errno)); fprintf(stderr, "Disconnect cam\n"); } //void V4L1_Base::staticCallFrame(void *p) //{ // ((V4L1_Base *) p)->updateFrame(0, NULL); //} //void V4L1_Base::staticUpdateFrame(int /*d*/, void *p) //{ // ((V4L1_Base *) p)->updateFrame(0, NULL); //} void V4L1_Base::newFrame() { switch (picture_format.palette) { case VIDEO_PALETTE_GREY: memcpy(YBuf,mmapFrame(),window.width * window.height); break; case VIDEO_PALETTE_YUV420P: memcpy(YBuf,mmapFrame(), window.width * window.height); memcpy(UBuf, mmapFrame()+ window.width * window.height, (window.width/2) * (window.height/2)); memcpy(VBuf, mmapFrame()+ window.width * window.height+(window.width/2) * (window.height/2), (window.width/2) * (window.height/2)); break; case VIDEO_PALETTE_YUYV: ccvt_yuyv_420p(window.width,window.height, mmapFrame(), YBuf, UBuf, VBuf); break; case VIDEO_PALETTE_RGB24: RGB2YUV(window.width, window.height, mmapFrame(), YBuf, UBuf, VBuf, 0); break; default: cerr << "invalid palette " <newFrame(); } int V4L1_Base::start_capturing(char * /*errmsg*/) { mmapCapture(); mmapSync(); selectCallBackID = IEAddCallback(fd, updateFrame, this); //newFrame(); return 0; } int V4L1_Base::stop_capturing(char * /*errmsg*/) { IERmCallback(selectCallBackID); selectCallBackID = -1; return 0; } int V4L1_Base::getWidth() { return window.width; } int V4L1_Base::getHeight() { return window.height; } void V4L1_Base::setFPS(int fps) { frameRate = fps; } int V4L1_Base::getFPS() { return frameRate; } char * V4L1_Base::getDeviceName() { return capability.name; } void V4L1_Base::init(int preferedPalette) { if (preferedPalette) { picture_format.palette=preferedPalette; if (0 == ioctl(fd, VIDIOCSPICT, &picture_format)) cerr << "found preferedPalette " << preferedPalette << endl; else { preferedPalette=0; cerr << "preferedPalette " << preferedPalette << " invalid, trying to find one." << endl; } } if (preferedPalette == 0) { do { /* trying VIDEO_PALETTE_YUV420P (Planar) */ picture_format.palette=VIDEO_PALETTE_YUV420P; if (0 == ioctl(fd, VIDIOCSPICT, &picture_format)) { cerr << "found palette VIDEO_PALETTE_YUV420P" << endl; break; } cerr << "VIDEO_PALETTE_YUV420P not supported." << endl; /* trying VIDEO_PALETTE_YUV420 (interlaced) */ picture_format.palette=VIDEO_PALETTE_YUV420; if ( 0== ioctl(fd, VIDIOCSPICT, &picture_format)) { cerr << "found palette VIDEO_PALETTE_YUV420" << endl; break; } cerr << "VIDEO_PALETTE_YUV420 not supported." << endl; /* trying VIDEO_PALETTE_RGB24 */ picture_format.palette=VIDEO_PALETTE_RGB24; if ( 0== ioctl(fd, VIDIOCSPICT, &picture_format)) { cerr << "found palette VIDEO_PALETTE_RGB24" << endl; break; } cerr << "VIDEO_PALETTE_RGB24 not supported." << endl; /* trying VIDEO_PALETTE_GREY */ picture_format.palette=VIDEO_PALETTE_GREY; if ( 0== ioctl(fd, VIDIOCSPICT, &picture_format)) { cerr << "found palette VIDEO_PALETTE_GREY" << endl; break; } cerr << "VIDEO_PALETTE_GREY not supported." << endl; cerr << "could not find a supported palette." << endl; exit(1); } while (false); } allocBuffers(); } void V4L1_Base::allocBuffers() { delete YBuf; delete UBuf; delete VBuf; delete colorBuffer; YBuf= new unsigned char[window.width * window.height]; UBuf= new unsigned char[window.width * window.height]; VBuf= new unsigned char[window.width * window.height]; colorBuffer = new unsigned char[window.width * window.height * 4]; } void V4L1_Base::checkSize(int & x, int & y) { if (x >= capability.maxwidth && y >= capability.maxheight) { x=capability.maxwidth; y=capability.maxheight; } else if (x>=352 && y >=288) { x=352;y=288; } else if (x>=320 && y >= 240) { x=320;y=240; } else if (x>=176 && y >=144) { x=176;y=144; } else if (x>=160 && y >=120 ) { x=160;y=120; } else { x=capability.minwidth; y=capability.minheight; } } void V4L1_Base::getMaxMinSize(int & xmax, int & ymax, int & xmin, int & ymin) { xmax = capability.maxwidth; ymax = capability.maxheight; xmin = capability.minwidth; ymin = capability.minheight; } bool V4L1_Base::setSize(int x, int y) { int oldX, oldY; checkSize(x,y); oldX = window.width; oldY = window.height; window.width=x; window.height=y; cerr << "New size is x=" << window.width << " " << "y=" << window.height <