/*************************************************************************** copyright : (C) 2007 by Sebastian Held email : sebastian.held@gmx.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of version 2 of the GNU General Public License as * * published by the Free Software Foundation; * * * ***************************************************************************/ // uses code from xawtv: webcam.c (c) 1998-2002 Gerd Knorr //#include //#include #include /* low-level i/o */ //#include #include //#include //#include //#include //#include //#include #include //#include /* for videodev2.h */ #include "barcode_v4l.h" #include "../tellico_debug.h" using barcodeRecognition::ng_vid_driver; using barcodeRecognition::ng_vid_driver_v4l; using barcodeRecognition::barcode_v4l; using barcodeRecognition::video_converter; TQPtrList barcodeRecognition::ng_vid_driver::m_converter; const char *barcodeRecognition::device_cap[] = { "capture", "tuner", "teletext", "overlay", "chromakey", "clipping", "frameram", "scales", "monochrome", 0 }; const unsigned int barcodeRecognition::ng_vfmt_to_depth[] = { 0, /* unused */ 8, /* RGB8 */ 8, /* GRAY8 */ 16, /* RGB15 LE */ 16, /* RGB16 LE */ 16, /* RGB15 BE */ 16, /* RGB16 BE */ 24, /* BGR24 */ 32, /* BGR32 */ 24, /* RGB24 */ 32, /* RGB32 */ 16, /* LUT2 */ 32, /* LUT4 */ 16, /* YUYV */ 16, /* YUV422P */ 12, /* YUV420P */ 0, /* MJPEG */ 0, /* JPEG */ 16, /* UYVY */ }; const char* barcodeRecognition::ng_vfmt_to_desc[] = { "none", "8 bit PseudoColor (dithering)", "8 bit StaticGray", "15 bit TrueColor (LE)", "16 bit TrueColor (LE)", "15 bit TrueColor (BE)", "16 bit TrueColor (BE)", "24 bit TrueColor (LE: bgr)", "32 bit TrueColor (LE: bgr-)", "24 bit TrueColor (BE: rgb)", "32 bit TrueColor (BE: -rgb)", "16 bit TrueColor (lut)", "32 bit TrueColor (lut)", "16 bit YUV 4:2:2 (packed, YUYV)", "16 bit YUV 4:2:2 (planar)", "12 bit YUV 4:2:0 (planar)", "MJPEG (AVI)", "JPEG (JFIF)", "16 bit YUV 4:2:2 (packed, UYVY)", }; unsigned int barcodeRecognition::ng_yuv_gray[256]; unsigned int barcodeRecognition::ng_yuv_red[256]; unsigned int barcodeRecognition::ng_yuv_blue[256]; unsigned int barcodeRecognition::ng_yuv_g1[256]; unsigned int barcodeRecognition::ng_yuv_g2[256]; unsigned int barcodeRecognition::ng_clip[256 + 2 * CLIP]; void barcodeRecognition::ng_color_yuv2rgb_init() { int i; # define RED_NULL 128 # define BLUE_NULL 128 # define LUN_MUL 256 # define RED_MUL 512 # define BLUE_MUL 512 #define GREEN1_MUL (-RED_MUL/2) #define GREEN2_MUL (-BLUE_MUL/6) #define RED_ADD (-RED_NULL * RED_MUL) #define BLUE_ADD (-BLUE_NULL * BLUE_MUL) #define GREEN1_ADD (-RED_ADD/2) #define GREEN2_ADD (-BLUE_ADD/6) /* init Lookup tables */ for (i = 0; i < 256; i++) { barcodeRecognition::ng_yuv_gray[i] = i * LUN_MUL >> 8; barcodeRecognition::ng_yuv_red[i] = (RED_ADD + i * RED_MUL) >> 8; barcodeRecognition::ng_yuv_blue[i] = (BLUE_ADD + i * BLUE_MUL) >> 8; barcodeRecognition::ng_yuv_g1[i] = (GREEN1_ADD + i * GREEN1_MUL) >> 8; barcodeRecognition::ng_yuv_g2[i] = (GREEN2_ADD + i * GREEN2_MUL) >> 8; } for (i = 0; i < CLIP; i++) barcodeRecognition::ng_clip[i] = 0; for (; i < CLIP + 256; i++) barcodeRecognition::ng_clip[i] = i - CLIP; for (; i < 2 * CLIP + 256; i++) barcodeRecognition::ng_clip[i] = 255; } barcode_v4l::barcode_v4l() { m_devname = "/dev/video0"; m_grab_width = 640; m_grab_height = 480; m_drv = 0; m_conv = 0; barcodeRecognition::ng_color_yuv2rgb_init(); //ng_vid_driver::register_video_converter( new barcodeRecognition::yuv422p_to_rgb24() ); //ng_vid_driver::register_video_converter( new barcodeRecognition::yuv422_to_rgb24() ); ng_vid_driver::register_video_converter( new barcodeRecognition::yuv420p_to_rgb24() ); grab_init(); } barcode_v4l::~barcode_v4l() { if (m_drv) { m_drv->close(); delete m_drv; } } bool barcode_v4l::isOpen() { return m_drv; } TQImage barcode_v4l::grab_one2() { if (!m_drv) { myDebug() << "no driver/device available" << endl; return TQImage(); } TQByteArray *cap; if (!(cap = m_drv->getimage2())) { myDebug() << "capturing image failed" << endl; return TQImage(); } TQByteArray *buf; if (m_conv) { buf = new TQByteArray( 3*m_fmt.width*m_fmt.height ); m_conv->frame( buf, cap, m_fmt_drv ); } else { buf = new TQByteArray(*cap); } delete cap; int depth = 32; TQByteArray *buf2 = new TQByteArray( depth/8 *m_fmt.width*m_fmt.height ); for (uint i=0; iat(i*3+2); (*buf2)[i*4+1] = buf->at(i*3+1); (*buf2)[i*4+2] = buf->at(i*3+0); (*buf2)[i*4+3] = 0; } delete buf; TQImage *temp = new TQImage( (uchar*)buf2->data(), m_fmt.width, m_fmt.height, depth, 0, 0, TQImage::LittleEndian ); TQImage temp2 = temp->copy(); delete temp; delete buf2; return temp2; } bool barcode_v4l::grab_init() { m_drv = ng_vid_driver::createDriver( m_devname ); if (!m_drv) { myDebug() << "no grabber device available" << endl; return false; } if (!(m_drv->capabilities() & CAN_CAPTURE)) { myDebug() << "device doesn't support capture" << endl; m_drv->close(); delete m_drv; m_drv = 0; return false; } /* try native */ m_fmt.fmtid = VIDEO_RGB24; m_fmt.width = m_grab_width; m_fmt.height = m_grab_height; if (m_drv->setformat( &m_fmt )) { m_fmt_drv = m_fmt; return true; } /* check all available conversion functions */ m_fmt.bytesperline = m_fmt.width * ng_vfmt_to_depth[m_fmt.fmtid] / 8; for (int i = 0; ifmtid_in(); m_fmt_drv.bytesperline = 0; if (m_drv->setformat( &m_fmt_drv )) { m_fmt.width = m_fmt_drv.width; m_fmt.height = m_fmt_drv.height; m_conv = conv; //m_conv->init( &m_fmt ); return true; } } myDebug() << "can't get rgb24 data" << endl; m_drv->close(); delete m_drv; m_drv = 0; return false; } ng_vid_driver* ng_vid_driver::createDriver( TQString device ) { /* check all grabber drivers */ ng_vid_driver *drv = new ng_vid_driver_v4l(); if (!drv->open2( device )) { myDebug() << "no v4l device found" << endl; delete drv; drv = 0; } return drv; } int ng_vid_driver::xioctl( int fd, int cmd, void *arg ) { int rc; rc = ioctl(fd,cmd,arg); if (rc == 0) return 0; //print_ioctl(stderr,ioctls_v4l1,PREFIX,cmd,arg); qDebug( ": %s\n",(rc == 0) ? "ok" : strerror(errno) ); return rc; } void ng_vid_driver::register_video_converter( video_converter *conv ) { if (!conv) return; m_converter.append( conv ); } video_converter *ng_vid_driver::find_video_converter( int out, int in ) { video_converter *conv; for (conv = m_converter.first(); conv; conv = m_converter.next() ) if ((conv->fmtid_in() == in) && (conv->fmtid_out() == out)) return conv; return 0; } ng_vid_driver_v4l::ng_vid_driver_v4l() { m_name = "v4l"; m_drv = 0; m_fd = -1; m_use_read = false; for (int i=0; i %dx%d", m_capability.minwidth, m_capability.minheight, m_capability.maxwidth, m_capability.maxheight ); #endif #ifdef Barcode_DEBUG fprintf(stderr," v4l: using read() for capture\n"); #endif m_use_read = true; return true; } void ng_vid_driver_v4l::close() { #ifdef Barcode_DEBUG fprintf(stderr, "v4l: close\n"); #endif if (m_fd != -1) ::close(m_fd); m_fd = -1; return; } int ng_vid_driver_v4l::capabilities() { int ret = 0; if (m_capability.type & VID_TYPE_OVERLAY) ret |= CAN_OVERLAY; if (m_capability.type & VID_TYPE_CAPTURE) ret |= CAN_CAPTURE; if (m_capability.type & VID_TYPE_TUNER) ret |= CAN_TUNE; if (m_capability.type & VID_TYPE_CHROMAKEY) ret |= NEEDS_CHROMAKEY; return ret; } bool ng_vid_driver_v4l::setformat( ng_video_fmt *fmt ) { bool rc = false; #ifdef Barcode_DEBUG fprintf(stderr,"v4l: setformat\n"); #endif if (m_use_read) { rc = read_setformat( fmt ); } else { Q_ASSERT( false ); } m_fmt = *fmt; return rc; } bool ng_vid_driver_v4l::read_setformat( ng_video_fmt *fmt ) { xioctl( m_fd, VIDIOCGCAP, &m_capability ); if (fmt->width > static_cast(m_capability.maxwidth)) fmt->width = m_capability.maxwidth; if (fmt->height > static_cast(m_capability.maxheight)) fmt->height = m_capability.maxheight; fmt->bytesperline = fmt->width * ng_vfmt_to_depth[fmt->fmtid] / 8; xioctl( m_fd, VIDIOCGPICT, &m_pict ); m_pict.depth = ng_vfmt_to_depth[fmt->fmtid]; m_pict.palette = GETELEM(format2palette,fmt->fmtid,0); m_pict.brightness = 20000; if (-1 == xioctl( m_fd, VIDIOCSPICT, &m_pict )) return false; xioctl( m_fd, VIDIOCGWIN, &m_win); m_win.width = m_fmt.width; m_win.height = m_fmt.height; m_win.clipcount = 0; if (-1 == xioctl( m_fd, VIDIOCSWIN, &m_win )) return false; return true; } TQByteArray* ng_vid_driver_v4l::getimage2() { #ifdef Barcode_DEBUG myDebug() << "v4l: getimage2" << endl; #endif return read_getframe2(); } TQByteArray* ng_vid_driver_v4l::read_getframe2() { TQByteArray* buf; int size; size = m_fmt.bytesperline * m_fmt.height; buf = new TQByteArray( size ); if (size != read( m_fd, buf->data(), size )) { delete( buf ); return 0; } return buf; } #define GRAY(val) barcodeRecognition::ng_yuv_gray[val] #define RED(gray,red) ng_clip[ CLIP + gray + barcodeRecognition::ng_yuv_red[red] ] #define GREEN(gray,red,blue) ng_clip[ CLIP + gray + barcodeRecognition::ng_yuv_g1[red] + \ barcodeRecognition::ng_yuv_g2[blue] ] #define BLUE(gray,blue) ng_clip[ CLIP + gray + barcodeRecognition::ng_yuv_blue[blue] ] void barcodeRecognition::yuv420p_to_rgb24::frame( TQByteArray *out, const TQByteArray *in, const ng_video_fmt fmt ) { unsigned char *y, *u, *v, *d; unsigned char *us,*vs; unsigned char *dp; unsigned int i,j; int gray; dp = (unsigned char*)out->data(); y = (unsigned char*)in->data(); u = y + fmt.width * fmt.height; v = u + fmt.width * fmt.height / 4; for (i = 0; i < fmt.height; i++) { d = dp; us = u; vs = v; for (j = 0; j < fmt.width; j+= 2) { gray = GRAY(*y); *(d++) = RED(gray,*v); *(d++) = GREEN(gray,*v,*u); *(d++) = BLUE(gray,*u); y++; gray = GRAY(*y); *(d++) = RED(gray,*v); *(d++) = GREEN(gray,*v,*u); *(d++) = BLUE(gray,*u); y++; u++; v++; } if (0 == (i % 2)) { u = us; v = vs; } dp += 3*fmt.width; } }