#include "Camera.h" #include #include // errono #include #include // ioctl #include // PROT_READ #include "MStopwatch.h" #include "videodev.h" ClassImp(Camera); using namespace std; inline int Camera::Ioctl(int req, void *opt, const char *str) { int rc = ioctl(fd, req, opt); if (rc==-1) { cout << "Error! Ioctl " << req << ": "; cout << (str?str:strerror(errno)) << " (rc=" << rc << ")" << endl; } return rc; } void Camera::Error(const char *str, int fatal) { cout << endl << (fatal?"Fatal ":"") << "Error! " << str << ": " << strerror(errno) << endl; if (fatal) exit(1); } void Camera::SigInit() { return; struct sigaction act, old; memset(&act, 0, sizeof(act)); act.sa_handler = SigAlarm; sigemptyset(&act. sa_mask); sigaction(SIGALRM, &act, &old); // signal(SIGINT, ctrlc); } void Camera::SigAlarm(int signal) { cout << "Camera: oops: got sigalarm" << endl; exit(1); } char *Camera::GetImg(unsigned int frame) { // wait until grabbing is finished?? // // give signal SIGALARM const int SYNC_TIMEOUT = 1; alarm(SYNC_TIMEOUT); Ioctl(VIDIOCSYNC, &frame); // sync with mmap grabbing alarm(0); return pMapBuffer+iOffsets[frame]; } int Camera::StartGrab(unsigned int frame) { static struct video_mmap gb = { 0, // frame rows, cols, // height, width VIDEO_PALETTE_RGB24 // palette }; gb.frame = frame&1; // // capture frame // if (Ioctl(VIDIOCMCAPTURE, &gb) != -1) return true; if (errno == EAGAIN) cout << "Grabber chip can't sync" << endl; return false; } Camera::Camera(PixClient &client) : fd(-1), iBufferSize(0), fClient(client), fMutex(), fCond(&fMutex) { cout << "Starting thread..." << flush; //pthread_cond_init(&fCond, NULL); //pthread_mutex_init(&fMux, NULL); //pthread_mutex_lock(&fMux); fMutex.Lock(); pthread_create(&fThread, NULL, MapThread, this); cout << "done." << endl; cout << "/dev/video: opening..." << flush; // // ------ Open device /dev/video ------ // do { fd = open("/dev/video", O_RDWR); usleep(1); } while (errno==19 && fd==-1); if (fd == -1) Error("open /dev/video"); fcntl(fd, F_SETFD, FD_CLOEXEC); // Close device on exit SigInit(); // // get input channel 0 information // struct video_channel ch; ch.channel = 0; Ioctl(VIDIOCGCHAN, &ch); // // ioctl probe, switch to input 0 // Ioctl(VIDIOCSCHAN, &ch, "You need a bttv version > 0.5.13"); // // map grab buffer, get size and offset // struct video_mbuf buffers; Ioctl(VIDIOCGMBUF, &buffers); iBufferSize = buffers.size; iOffsets[0] = buffers.offsets[0]; iOffsets[1] = buffers.offsets[1]; // // map file (device) into memory // pMapBuffer = (char*)mmap(0, iBufferSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if ((int)pMapBuffer == -1) Error("mmap"); cout << "OK." << endl; cout << "Buffer Address: " << (void*)pMapBuffer << endl; cout << "Buffer Offset 1: " << (void*)iOffsets[0] << endl; cout << "Buffer Offset 2: " << (void*)iOffsets[1] << endl; cout << "Buffer Size: " << (void*)iBufferSize << endl; cout << "grab: use: 768x576 24 bit TrueColor (LE: bgr) = " << (void*)(768*576*3) << "b" << endl; } Camera::~Camera() { cout << "Stopping thread..." << flush; pthread_cancel(fThread); //pthread_mutex_destroy(&fMux); //pthread_cond_destroy(&fCond); cout << "done." << endl; cout << "/dev/video: closing... " << flush; // unmap device memory if ((int)pMapBuffer != -1) munmap(pMapBuffer, iBufferSize); if (fd != -1) { close(fd); fd = -1; } cout << " Done." << endl; } void *Camera::MapThread(void *arg) { Camera *cam = (Camera*)arg; // setpriority(PRIO_PROCESS, 0, 10); pthread_detach(pthread_self()); cam->Thread(); return 0; } void Camera::LoopStep(const unsigned long n) { char *img = GetImg(n&1); gettimeofday(&fTime, NULL); const char *end = img + cols*rows*depth; char *beg = fImg; while (img < end) { *beg++ = *img; img += depth; } } void Camera::Thread() { #define IsOdd(i) (2*(i/2)!=i) while (1) { //pthread_cond_wait(&fCond, &fMux); fCond.Wait(); MStopwatch t; t.Start(); unsigned long i=0; if (!StartGrab(0)) continue; if (!StartGrab(1)) continue; while (!(fStop || fNum && i==fNum-2)) { LoopStep(i); if (!StartGrab(i&1)) break; fClient.ProcessFrame(i, (byte*)fImg, &fTime); i++; } if (!IsOdd(i)) { LoopStep(i); fClient.ProcessFrame(i, (byte*)fImg, &fTime); i++; } LoopStep(i); fClient.ProcessFrame(i, (byte*)fImg, &fTime); i++; // // Wait until processing of frame 1 finished. // t.Stop(); t.Print(i); fRunning = 0; } } void Camera::Loop(unsigned long nof) { if (2*(nof/2) != nof) { cout << "Sorry, only even values are allowed!" << endl; return; } // // Stop running loop // fStop = 1; // // Wait until loop is stopped (pthread_cond_wait is executing) // set new number of frames to process // fMutex.Lock(); //pthread_mutex_lock(&fMux); fNum = nof; fStop = 0; fRunning = 1; fMutex.UnLock(); //pthread_mutex_unlock(&fMux); // // Start execution // fCond.Broadcast(); //pthread_cond_signal(&fCond); } void Camera::SetPicPar(int bright, int hue, int contrast) { struct video_picture pict; Ioctl(VIDIOCGPICT, &pict); // get if (contrast != -1) pict.contrast = contrast; if (bright != -1) pict.brightness = bright; if (hue != -1) pict.hue = hue; Ioctl(VIDIOCSPICT, &pict); //set } void Camera::GetPicPar(int *bright, int *hue, int *contrast) { struct video_picture pict; Ioctl(VIDIOCGPICT, &pict); // get *contrast = pict.contrast; *bright = pict.brightness; *hue = pict.hue; }